1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018, NVIDIA CORPORATION.
4 */
5
6#include <linux/genalloc.h>
7#include <linux/io.h>
8#include <linux/mailbox_client.h>
9#include <linux/of_address.h>
10#include <linux/platform_device.h>
11
12#include <soc/tegra/bpmp.h>
13#include <soc/tegra/bpmp-abi.h>
14#include <soc/tegra/ivc.h>
15
16#include "bpmp-private.h"
17
18struct tegra186_bpmp {
19	struct tegra_bpmp *parent;
20
21	struct {
22		struct gen_pool *pool;
23		union {
24			void __iomem *sram;
25			void *dram;
26		};
27		dma_addr_t phys;
28	} tx, rx;
29
30	struct {
31		struct mbox_client client;
32		struct mbox_chan *channel;
33	} mbox;
34};
35
36static inline struct tegra_bpmp *
37mbox_client_to_bpmp(struct mbox_client *client)
38{
39	struct tegra186_bpmp *priv;
40
41	priv = container_of(client, struct tegra186_bpmp, mbox.client);
42
43	return priv->parent;
44}
45
46static bool tegra186_bpmp_is_message_ready(struct tegra_bpmp_channel *channel)
47{
48	int err;
49
50	err = tegra_ivc_read_get_next_frame(channel->ivc, &channel->ib);
51	if (err) {
52		iosys_map_clear(&channel->ib);
53		return false;
54	}
55
56	return true;
57}
58
59static bool tegra186_bpmp_is_channel_free(struct tegra_bpmp_channel *channel)
60{
61	int err;
62
63	err = tegra_ivc_write_get_next_frame(channel->ivc, &channel->ob);
64	if (err) {
65		iosys_map_clear(&channel->ob);
66		return false;
67	}
68
69	return true;
70}
71
72static int tegra186_bpmp_ack_message(struct tegra_bpmp_channel *channel)
73{
74	return tegra_ivc_read_advance(channel->ivc);
75}
76
77static int tegra186_bpmp_post_message(struct tegra_bpmp_channel *channel)
78{
79	return tegra_ivc_write_advance(channel->ivc);
80}
81
82static int tegra186_bpmp_ring_doorbell(struct tegra_bpmp *bpmp)
83{
84	struct tegra186_bpmp *priv = bpmp->priv;
85	int err;
86
87	err = mbox_send_message(priv->mbox.channel, NULL);
88	if (err < 0)
89		return err;
90
91	mbox_client_txdone(priv->mbox.channel, 0);
92
93	return 0;
94}
95
96static void tegra186_bpmp_ivc_notify(struct tegra_ivc *ivc, void *data)
97{
98	struct tegra_bpmp *bpmp = data;
99	struct tegra186_bpmp *priv = bpmp->priv;
100
101	if (WARN_ON(priv->mbox.channel == NULL))
102		return;
103
104	tegra186_bpmp_ring_doorbell(bpmp);
105}
106
107static int tegra186_bpmp_channel_init(struct tegra_bpmp_channel *channel,
108				      struct tegra_bpmp *bpmp,
109				      unsigned int index)
110{
111	struct tegra186_bpmp *priv = bpmp->priv;
112	size_t message_size, queue_size;
113	struct iosys_map rx, tx;
114	unsigned int offset;
115	int err;
116
117	channel->ivc = devm_kzalloc(bpmp->dev, sizeof(*channel->ivc),
118				    GFP_KERNEL);
119	if (!channel->ivc)
120		return -ENOMEM;
121
122	message_size = tegra_ivc_align(MSG_MIN_SZ);
123	queue_size = tegra_ivc_total_queue_size(message_size);
124	offset = queue_size * index;
125
126	if (priv->rx.pool) {
127		iosys_map_set_vaddr_iomem(&rx, priv->rx.sram + offset);
128		iosys_map_set_vaddr_iomem(&tx, priv->tx.sram + offset);
129	} else {
130		iosys_map_set_vaddr(&rx, priv->rx.dram + offset);
131		iosys_map_set_vaddr(&tx, priv->tx.dram + offset);
132	}
133
134	err = tegra_ivc_init(channel->ivc, NULL, &rx, priv->rx.phys + offset, &tx,
135			     priv->tx.phys + offset, 1, message_size, tegra186_bpmp_ivc_notify,
136			     bpmp);
137	if (err < 0) {
138		dev_err(bpmp->dev, "failed to setup IVC for channel %u: %d\n",
139			index, err);
140		return err;
141	}
142
143	init_completion(&channel->completion);
144	channel->bpmp = bpmp;
145
146	return 0;
147}
148
149static void tegra186_bpmp_channel_reset(struct tegra_bpmp_channel *channel)
150{
151	/* reset the channel state */
152	tegra_ivc_reset(channel->ivc);
153
154	/* sync the channel state with BPMP */
155	while (tegra_ivc_notified(channel->ivc))
156		;
157}
158
159static void tegra186_bpmp_channel_cleanup(struct tegra_bpmp_channel *channel)
160{
161	tegra_ivc_cleanup(channel->ivc);
162}
163
164static void mbox_handle_rx(struct mbox_client *client, void *data)
165{
166	struct tegra_bpmp *bpmp = mbox_client_to_bpmp(client);
167
168	tegra_bpmp_handle_rx(bpmp);
169}
170
171static void tegra186_bpmp_teardown_channels(struct tegra_bpmp *bpmp)
172{
173	struct tegra186_bpmp *priv = bpmp->priv;
174	unsigned int i;
175
176	for (i = 0; i < bpmp->threaded.count; i++) {
177		if (!bpmp->threaded_channels[i].bpmp)
178			continue;
179
180		tegra186_bpmp_channel_cleanup(&bpmp->threaded_channels[i]);
181	}
182
183	tegra186_bpmp_channel_cleanup(bpmp->rx_channel);
184	tegra186_bpmp_channel_cleanup(bpmp->tx_channel);
185
186	if (priv->tx.pool) {
187		gen_pool_free(priv->tx.pool, (unsigned long)priv->tx.sram, 4096);
188		gen_pool_free(priv->rx.pool, (unsigned long)priv->rx.sram, 4096);
189	}
190}
191
192static int tegra186_bpmp_dram_init(struct tegra_bpmp *bpmp)
193{
194	struct tegra186_bpmp *priv = bpmp->priv;
195	struct device_node *np;
196	struct resource res;
197	size_t size;
198	int err;
199
200	np = of_parse_phandle(bpmp->dev->of_node, "memory-region", 0);
201	if (!np)
202		return -ENODEV;
203
204	err = of_address_to_resource(np, 0, &res);
205	if (err < 0) {
206		dev_warn(bpmp->dev, "failed to parse memory region: %d\n", err);
207		return err;
208	}
209
210	size = resource_size(&res);
211
212	if (size < SZ_8K) {
213		dev_warn(bpmp->dev, "DRAM region must be larger than 8 KiB\n");
214		return -EINVAL;
215	}
216
217	priv->tx.phys = res.start;
218	priv->rx.phys = res.start + SZ_4K;
219
220	priv->tx.dram = devm_memremap(bpmp->dev, priv->tx.phys, size,
221				      MEMREMAP_WC);
222	if (IS_ERR(priv->tx.dram)) {
223		err = PTR_ERR(priv->tx.dram);
224		dev_warn(bpmp->dev, "failed to map DRAM region: %d\n", err);
225		return err;
226	}
227
228	priv->rx.dram = priv->tx.dram + SZ_4K;
229
230	return 0;
231}
232
233static int tegra186_bpmp_sram_init(struct tegra_bpmp *bpmp)
234{
235	struct tegra186_bpmp *priv = bpmp->priv;
236	int err;
237
238	priv->tx.pool = of_gen_pool_get(bpmp->dev->of_node, "shmem", 0);
239	if (!priv->tx.pool) {
240		dev_err(bpmp->dev, "TX shmem pool not found\n");
241		return -EPROBE_DEFER;
242	}
243
244	priv->tx.sram = (void __iomem *)gen_pool_dma_alloc(priv->tx.pool, 4096,
245							   &priv->tx.phys);
246	if (!priv->tx.sram) {
247		dev_err(bpmp->dev, "failed to allocate from TX pool\n");
248		return -ENOMEM;
249	}
250
251	priv->rx.pool = of_gen_pool_get(bpmp->dev->of_node, "shmem", 1);
252	if (!priv->rx.pool) {
253		dev_err(bpmp->dev, "RX shmem pool not found\n");
254		err = -EPROBE_DEFER;
255		goto free_tx;
256	}
257
258	priv->rx.sram = (void __iomem *)gen_pool_dma_alloc(priv->rx.pool, 4096,
259							   &priv->rx.phys);
260	if (!priv->rx.sram) {
261		dev_err(bpmp->dev, "failed to allocate from RX pool\n");
262		err = -ENOMEM;
263		goto free_tx;
264	}
265
266	return 0;
267
268free_tx:
269	gen_pool_free(priv->tx.pool, (unsigned long)priv->tx.sram, 4096);
270
271	return err;
272}
273
274static int tegra186_bpmp_setup_channels(struct tegra_bpmp *bpmp)
275{
276	unsigned int i;
277	int err;
278
279	err = tegra186_bpmp_dram_init(bpmp);
280	if (err == -ENODEV) {
281		err = tegra186_bpmp_sram_init(bpmp);
282		if (err < 0)
283			return err;
284	}
285
286	err = tegra186_bpmp_channel_init(bpmp->tx_channel, bpmp,
287					 bpmp->soc->channels.cpu_tx.offset);
288	if (err < 0)
289		return err;
290
291	err = tegra186_bpmp_channel_init(bpmp->rx_channel, bpmp,
292					 bpmp->soc->channels.cpu_rx.offset);
293	if (err < 0) {
294		tegra186_bpmp_channel_cleanup(bpmp->tx_channel);
295		return err;
296	}
297
298	for (i = 0; i < bpmp->threaded.count; i++) {
299		unsigned int index = bpmp->soc->channels.thread.offset + i;
300
301		err = tegra186_bpmp_channel_init(&bpmp->threaded_channels[i],
302						 bpmp, index);
303		if (err < 0)
304			break;
305	}
306
307	if (err < 0)
308		tegra186_bpmp_teardown_channels(bpmp);
309
310	return err;
311}
312
313static void tegra186_bpmp_reset_channels(struct tegra_bpmp *bpmp)
314{
315	unsigned int i;
316
317	/* reset message channels */
318	tegra186_bpmp_channel_reset(bpmp->tx_channel);
319	tegra186_bpmp_channel_reset(bpmp->rx_channel);
320
321	for (i = 0; i < bpmp->threaded.count; i++)
322		tegra186_bpmp_channel_reset(&bpmp->threaded_channels[i]);
323}
324
325static int tegra186_bpmp_init(struct tegra_bpmp *bpmp)
326{
327	struct tegra186_bpmp *priv;
328	int err;
329
330	priv = devm_kzalloc(bpmp->dev, sizeof(*priv), GFP_KERNEL);
331	if (!priv)
332		return -ENOMEM;
333
334	priv->parent = bpmp;
335	bpmp->priv = priv;
336
337	err = tegra186_bpmp_setup_channels(bpmp);
338	if (err < 0)
339		return err;
340
341	/* mbox registration */
342	priv->mbox.client.dev = bpmp->dev;
343	priv->mbox.client.rx_callback = mbox_handle_rx;
344	priv->mbox.client.tx_block = false;
345	priv->mbox.client.knows_txdone = false;
346
347	priv->mbox.channel = mbox_request_channel(&priv->mbox.client, 0);
348	if (IS_ERR(priv->mbox.channel)) {
349		err = PTR_ERR(priv->mbox.channel);
350		dev_err(bpmp->dev, "failed to get HSP mailbox: %d\n", err);
351		tegra186_bpmp_teardown_channels(bpmp);
352		return err;
353	}
354
355	tegra186_bpmp_reset_channels(bpmp);
356
357	return 0;
358}
359
360static void tegra186_bpmp_deinit(struct tegra_bpmp *bpmp)
361{
362	struct tegra186_bpmp *priv = bpmp->priv;
363
364	mbox_free_channel(priv->mbox.channel);
365
366	tegra186_bpmp_teardown_channels(bpmp);
367}
368
369static int tegra186_bpmp_resume(struct tegra_bpmp *bpmp)
370{
371	tegra186_bpmp_reset_channels(bpmp);
372
373	return 0;
374}
375
376const struct tegra_bpmp_ops tegra186_bpmp_ops = {
377	.init = tegra186_bpmp_init,
378	.deinit = tegra186_bpmp_deinit,
379	.is_response_ready = tegra186_bpmp_is_message_ready,
380	.is_request_ready = tegra186_bpmp_is_message_ready,
381	.ack_response = tegra186_bpmp_ack_message,
382	.ack_request = tegra186_bpmp_ack_message,
383	.is_response_channel_free = tegra186_bpmp_is_channel_free,
384	.is_request_channel_free = tegra186_bpmp_is_channel_free,
385	.post_response = tegra186_bpmp_post_message,
386	.post_request = tegra186_bpmp_post_message,
387	.ring_doorbell = tegra186_bpmp_ring_doorbell,
388	.resume = tegra186_bpmp_resume,
389};
390