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