• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2018, NVIDIA CORPORATION.
4  */
5 
6 #include <linux/genalloc.h>
7 #include <linux/mailbox_client.h>
8 #include <linux/platform_device.h>
9 
10 #include <soc/tegra/bpmp.h>
11 #include <soc/tegra/bpmp-abi.h>
12 #include <soc/tegra/ivc.h>
13 
14 #include "bpmp-private.h"
15 
16 struct tegra186_bpmp {
17 	struct tegra_bpmp *parent;
18 
19 	struct {
20 		struct gen_pool *pool;
21 		dma_addr_t phys;
22 		void *virt;
23 	} tx, rx;
24 
25 	struct {
26 		struct mbox_client client;
27 		struct mbox_chan *channel;
28 	} mbox;
29 };
30 
31 static inline struct tegra_bpmp *
mbox_client_to_bpmp(struct mbox_client * client)32 mbox_client_to_bpmp(struct mbox_client *client)
33 {
34 	struct tegra186_bpmp *priv;
35 
36 	priv = container_of(client, struct tegra186_bpmp, mbox.client);
37 
38 	return priv->parent;
39 }
40 
tegra186_bpmp_is_message_ready(struct tegra_bpmp_channel * channel)41 static bool tegra186_bpmp_is_message_ready(struct tegra_bpmp_channel *channel)
42 {
43 	void *frame;
44 
45 	frame = tegra_ivc_read_get_next_frame(channel->ivc);
46 	if (IS_ERR(frame)) {
47 		channel->ib = NULL;
48 		return false;
49 	}
50 
51 	channel->ib = frame;
52 
53 	return true;
54 }
55 
tegra186_bpmp_is_channel_free(struct tegra_bpmp_channel * channel)56 static bool tegra186_bpmp_is_channel_free(struct tegra_bpmp_channel *channel)
57 {
58 	void *frame;
59 
60 	frame = tegra_ivc_write_get_next_frame(channel->ivc);
61 	if (IS_ERR(frame)) {
62 		channel->ob = NULL;
63 		return false;
64 	}
65 
66 	channel->ob = frame;
67 
68 	return true;
69 }
70 
tegra186_bpmp_ack_message(struct tegra_bpmp_channel * channel)71 static int tegra186_bpmp_ack_message(struct tegra_bpmp_channel *channel)
72 {
73 	return tegra_ivc_read_advance(channel->ivc);
74 }
75 
tegra186_bpmp_post_message(struct tegra_bpmp_channel * channel)76 static int tegra186_bpmp_post_message(struct tegra_bpmp_channel *channel)
77 {
78 	return tegra_ivc_write_advance(channel->ivc);
79 }
80 
tegra186_bpmp_ring_doorbell(struct tegra_bpmp * bpmp)81 static int tegra186_bpmp_ring_doorbell(struct tegra_bpmp *bpmp)
82 {
83 	struct tegra186_bpmp *priv = bpmp->priv;
84 	int err;
85 
86 	err = mbox_send_message(priv->mbox.channel, NULL);
87 	if (err < 0)
88 		return err;
89 
90 	mbox_client_txdone(priv->mbox.channel, 0);
91 
92 	return 0;
93 }
94 
tegra186_bpmp_ivc_notify(struct tegra_ivc * ivc,void * data)95 static void tegra186_bpmp_ivc_notify(struct tegra_ivc *ivc, void *data)
96 {
97 	struct tegra_bpmp *bpmp = data;
98 	struct tegra186_bpmp *priv = bpmp->priv;
99 
100 	if (WARN_ON(priv->mbox.channel == NULL))
101 		return;
102 
103 	tegra186_bpmp_ring_doorbell(bpmp);
104 }
105 
tegra186_bpmp_channel_init(struct tegra_bpmp_channel * channel,struct tegra_bpmp * bpmp,unsigned int index)106 static int tegra186_bpmp_channel_init(struct tegra_bpmp_channel *channel,
107 				      struct tegra_bpmp *bpmp,
108 				      unsigned int index)
109 {
110 	struct tegra186_bpmp *priv = bpmp->priv;
111 	size_t message_size, queue_size;
112 	unsigned int offset;
113 	int err;
114 
115 	channel->ivc = devm_kzalloc(bpmp->dev, sizeof(*channel->ivc),
116 				    GFP_KERNEL);
117 	if (!channel->ivc)
118 		return -ENOMEM;
119 
120 	message_size = tegra_ivc_align(MSG_MIN_SZ);
121 	queue_size = tegra_ivc_total_queue_size(message_size);
122 	offset = queue_size * index;
123 
124 	err = tegra_ivc_init(channel->ivc, NULL,
125 			     priv->rx.virt + offset, priv->rx.phys + offset,
126 			     priv->tx.virt + offset, priv->tx.phys + offset,
127 			     1, message_size, tegra186_bpmp_ivc_notify,
128 			     bpmp);
129 	if (err < 0) {
130 		dev_err(bpmp->dev, "failed to setup IVC for channel %u: %d\n",
131 			index, err);
132 		return err;
133 	}
134 
135 	init_completion(&channel->completion);
136 	channel->bpmp = bpmp;
137 
138 	return 0;
139 }
140 
tegra186_bpmp_channel_reset(struct tegra_bpmp_channel * channel)141 static void tegra186_bpmp_channel_reset(struct tegra_bpmp_channel *channel)
142 {
143 	/* reset the channel state */
144 	tegra_ivc_reset(channel->ivc);
145 
146 	/* sync the channel state with BPMP */
147 	while (tegra_ivc_notified(channel->ivc))
148 		;
149 }
150 
tegra186_bpmp_channel_cleanup(struct tegra_bpmp_channel * channel)151 static void tegra186_bpmp_channel_cleanup(struct tegra_bpmp_channel *channel)
152 {
153 	tegra_ivc_cleanup(channel->ivc);
154 }
155 
mbox_handle_rx(struct mbox_client * client,void * data)156 static void mbox_handle_rx(struct mbox_client *client, void *data)
157 {
158 	struct tegra_bpmp *bpmp = mbox_client_to_bpmp(client);
159 
160 	tegra_bpmp_handle_rx(bpmp);
161 }
162 
tegra186_bpmp_init(struct tegra_bpmp * bpmp)163 static int tegra186_bpmp_init(struct tegra_bpmp *bpmp)
164 {
165 	struct tegra186_bpmp *priv;
166 	unsigned int i;
167 	int err;
168 
169 	priv = devm_kzalloc(bpmp->dev, sizeof(*priv), GFP_KERNEL);
170 	if (!priv)
171 		return -ENOMEM;
172 
173 	bpmp->priv = priv;
174 	priv->parent = bpmp;
175 
176 	priv->tx.pool = of_gen_pool_get(bpmp->dev->of_node, "shmem", 0);
177 	if (!priv->tx.pool) {
178 		dev_err(bpmp->dev, "TX shmem pool not found\n");
179 		return -EPROBE_DEFER;
180 	}
181 
182 	priv->tx.virt = gen_pool_dma_alloc(priv->tx.pool, 4096, &priv->tx.phys);
183 	if (!priv->tx.virt) {
184 		dev_err(bpmp->dev, "failed to allocate from TX pool\n");
185 		return -ENOMEM;
186 	}
187 
188 	priv->rx.pool = of_gen_pool_get(bpmp->dev->of_node, "shmem", 1);
189 	if (!priv->rx.pool) {
190 		dev_err(bpmp->dev, "RX shmem pool not found\n");
191 		err = -EPROBE_DEFER;
192 		goto free_tx;
193 	}
194 
195 	priv->rx.virt = gen_pool_dma_alloc(priv->rx.pool, 4096, &priv->rx.phys);
196 	if (!priv->rx.virt) {
197 		dev_err(bpmp->dev, "failed to allocate from RX pool\n");
198 		err = -ENOMEM;
199 		goto free_tx;
200 	}
201 
202 	err = tegra186_bpmp_channel_init(bpmp->tx_channel, bpmp,
203 					 bpmp->soc->channels.cpu_tx.offset);
204 	if (err < 0)
205 		goto free_rx;
206 
207 	err = tegra186_bpmp_channel_init(bpmp->rx_channel, bpmp,
208 					 bpmp->soc->channels.cpu_rx.offset);
209 	if (err < 0)
210 		goto cleanup_tx_channel;
211 
212 	for (i = 0; i < bpmp->threaded.count; i++) {
213 		unsigned int index = bpmp->soc->channels.thread.offset + i;
214 
215 		err = tegra186_bpmp_channel_init(&bpmp->threaded_channels[i],
216 						 bpmp, index);
217 		if (err < 0)
218 			goto cleanup_channels;
219 	}
220 
221 	/* mbox registration */
222 	priv->mbox.client.dev = bpmp->dev;
223 	priv->mbox.client.rx_callback = mbox_handle_rx;
224 	priv->mbox.client.tx_block = false;
225 	priv->mbox.client.knows_txdone = false;
226 
227 	priv->mbox.channel = mbox_request_channel(&priv->mbox.client, 0);
228 	if (IS_ERR(priv->mbox.channel)) {
229 		err = PTR_ERR(priv->mbox.channel);
230 		dev_err(bpmp->dev, "failed to get HSP mailbox: %d\n", err);
231 		goto cleanup_channels;
232 	}
233 
234 	tegra186_bpmp_channel_reset(bpmp->tx_channel);
235 	tegra186_bpmp_channel_reset(bpmp->rx_channel);
236 
237 	for (i = 0; i < bpmp->threaded.count; i++)
238 		tegra186_bpmp_channel_reset(&bpmp->threaded_channels[i]);
239 
240 	return 0;
241 
242 cleanup_channels:
243 	for (i = 0; i < bpmp->threaded.count; i++) {
244 		if (!bpmp->threaded_channels[i].bpmp)
245 			continue;
246 
247 		tegra186_bpmp_channel_cleanup(&bpmp->threaded_channels[i]);
248 	}
249 
250 	tegra186_bpmp_channel_cleanup(bpmp->rx_channel);
251 cleanup_tx_channel:
252 	tegra186_bpmp_channel_cleanup(bpmp->tx_channel);
253 free_rx:
254 	gen_pool_free(priv->rx.pool, (unsigned long)priv->rx.virt, 4096);
255 free_tx:
256 	gen_pool_free(priv->tx.pool, (unsigned long)priv->tx.virt, 4096);
257 
258 	return err;
259 }
260 
tegra186_bpmp_deinit(struct tegra_bpmp * bpmp)261 static void tegra186_bpmp_deinit(struct tegra_bpmp *bpmp)
262 {
263 	struct tegra186_bpmp *priv = bpmp->priv;
264 	unsigned int i;
265 
266 	mbox_free_channel(priv->mbox.channel);
267 
268 	for (i = 0; i < bpmp->threaded.count; i++)
269 		tegra186_bpmp_channel_cleanup(&bpmp->threaded_channels[i]);
270 
271 	tegra186_bpmp_channel_cleanup(bpmp->rx_channel);
272 	tegra186_bpmp_channel_cleanup(bpmp->tx_channel);
273 
274 	gen_pool_free(priv->rx.pool, (unsigned long)priv->rx.virt, 4096);
275 	gen_pool_free(priv->tx.pool, (unsigned long)priv->tx.virt, 4096);
276 }
277 
tegra186_bpmp_resume(struct tegra_bpmp * bpmp)278 static int tegra186_bpmp_resume(struct tegra_bpmp *bpmp)
279 {
280 	unsigned int i;
281 
282 	/* reset message channels */
283 	tegra186_bpmp_channel_reset(bpmp->tx_channel);
284 	tegra186_bpmp_channel_reset(bpmp->rx_channel);
285 
286 	for (i = 0; i < bpmp->threaded.count; i++)
287 		tegra186_bpmp_channel_reset(&bpmp->threaded_channels[i]);
288 
289 	return 0;
290 }
291 
292 const struct tegra_bpmp_ops tegra186_bpmp_ops = {
293 	.init = tegra186_bpmp_init,
294 	.deinit = tegra186_bpmp_deinit,
295 	.is_response_ready = tegra186_bpmp_is_message_ready,
296 	.is_request_ready = tegra186_bpmp_is_message_ready,
297 	.ack_response = tegra186_bpmp_ack_message,
298 	.ack_request = tegra186_bpmp_ack_message,
299 	.is_response_channel_free = tegra186_bpmp_is_channel_free,
300 	.is_request_channel_free = tegra186_bpmp_is_channel_free,
301 	.post_response = tegra186_bpmp_post_message,
302 	.post_request = tegra186_bpmp_post_message,
303 	.ring_doorbell = tegra186_bpmp_ring_doorbell,
304 	.resume = tegra186_bpmp_resume,
305 };
306