1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018, NVIDIA CORPORATION.
6 #include <linux/genalloc.h>
7 #include <linux/mailbox_client.h>
8 #include <linux/platform_device.h>
10 #include <soc/tegra/bpmp.h>
11 #include <soc/tegra/bpmp-abi.h>
12 #include <soc/tegra/ivc.h>
14 #include "bpmp-private.h"
16 struct tegra186_bpmp
{
17 struct tegra_bpmp
*parent
;
20 struct gen_pool
*pool
;
26 struct mbox_client client
;
27 struct mbox_chan
*channel
;
31 static inline struct tegra_bpmp
*
32 mbox_client_to_bpmp(struct mbox_client
*client
)
34 struct tegra186_bpmp
*priv
;
36 priv
= container_of(client
, struct tegra186_bpmp
, mbox
.client
);
41 static bool tegra186_bpmp_is_message_ready(struct tegra_bpmp_channel
*channel
)
45 frame
= tegra_ivc_read_get_next_frame(channel
->ivc
);
56 static bool tegra186_bpmp_is_channel_free(struct tegra_bpmp_channel
*channel
)
60 frame
= tegra_ivc_write_get_next_frame(channel
->ivc
);
71 static int tegra186_bpmp_ack_message(struct tegra_bpmp_channel
*channel
)
73 return tegra_ivc_read_advance(channel
->ivc
);
76 static int tegra186_bpmp_post_message(struct tegra_bpmp_channel
*channel
)
78 return tegra_ivc_write_advance(channel
->ivc
);
81 static int tegra186_bpmp_ring_doorbell(struct tegra_bpmp
*bpmp
)
83 struct tegra186_bpmp
*priv
= bpmp
->priv
;
86 err
= mbox_send_message(priv
->mbox
.channel
, NULL
);
90 mbox_client_txdone(priv
->mbox
.channel
, 0);
95 static void tegra186_bpmp_ivc_notify(struct tegra_ivc
*ivc
, void *data
)
97 struct tegra_bpmp
*bpmp
= data
;
98 struct tegra186_bpmp
*priv
= bpmp
->priv
;
100 if (WARN_ON(priv
->mbox
.channel
== NULL
))
103 tegra186_bpmp_ring_doorbell(bpmp
);
106 static int tegra186_bpmp_channel_init(struct tegra_bpmp_channel
*channel
,
107 struct tegra_bpmp
*bpmp
,
110 struct tegra186_bpmp
*priv
= bpmp
->priv
;
111 size_t message_size
, queue_size
;
115 channel
->ivc
= devm_kzalloc(bpmp
->dev
, sizeof(*channel
->ivc
),
120 message_size
= tegra_ivc_align(MSG_MIN_SZ
);
121 queue_size
= tegra_ivc_total_queue_size(message_size
);
122 offset
= queue_size
* index
;
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
,
130 dev_err(bpmp
->dev
, "failed to setup IVC for channel %u: %d\n",
135 init_completion(&channel
->completion
);
136 channel
->bpmp
= bpmp
;
141 static void tegra186_bpmp_channel_reset(struct tegra_bpmp_channel
*channel
)
143 /* reset the channel state */
144 tegra_ivc_reset(channel
->ivc
);
146 /* sync the channel state with BPMP */
147 while (tegra_ivc_notified(channel
->ivc
))
151 static void tegra186_bpmp_channel_cleanup(struct tegra_bpmp_channel
*channel
)
153 tegra_ivc_cleanup(channel
->ivc
);
156 static void mbox_handle_rx(struct mbox_client
*client
, void *data
)
158 struct tegra_bpmp
*bpmp
= mbox_client_to_bpmp(client
);
160 tegra_bpmp_handle_rx(bpmp
);
163 static int tegra186_bpmp_init(struct tegra_bpmp
*bpmp
)
165 struct tegra186_bpmp
*priv
;
169 priv
= devm_kzalloc(bpmp
->dev
, sizeof(*priv
), GFP_KERNEL
);
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");
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");
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");
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");
202 err
= tegra186_bpmp_channel_init(bpmp
->tx_channel
, bpmp
,
203 bpmp
->soc
->channels
.cpu_tx
.offset
);
207 err
= tegra186_bpmp_channel_init(bpmp
->rx_channel
, bpmp
,
208 bpmp
->soc
->channels
.cpu_rx
.offset
);
210 goto cleanup_tx_channel
;
212 for (i
= 0; i
< bpmp
->threaded
.count
; i
++) {
213 unsigned int index
= bpmp
->soc
->channels
.thread
.offset
+ i
;
215 err
= tegra186_bpmp_channel_init(&bpmp
->threaded_channels
[i
],
218 goto cleanup_channels
;
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;
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
;
234 tegra186_bpmp_channel_reset(bpmp
->tx_channel
);
235 tegra186_bpmp_channel_reset(bpmp
->rx_channel
);
237 for (i
= 0; i
< bpmp
->threaded
.count
; i
++)
238 tegra186_bpmp_channel_reset(&bpmp
->threaded_channels
[i
]);
243 for (i
= 0; i
< bpmp
->threaded
.count
; i
++) {
244 if (!bpmp
->threaded_channels
[i
].bpmp
)
247 tegra186_bpmp_channel_cleanup(&bpmp
->threaded_channels
[i
]);
250 tegra186_bpmp_channel_cleanup(bpmp
->rx_channel
);
252 tegra186_bpmp_channel_cleanup(bpmp
->tx_channel
);
254 gen_pool_free(priv
->rx
.pool
, (unsigned long)priv
->rx
.virt
, 4096);
256 gen_pool_free(priv
->tx
.pool
, (unsigned long)priv
->tx
.virt
, 4096);
261 static void tegra186_bpmp_deinit(struct tegra_bpmp
*bpmp
)
263 struct tegra186_bpmp
*priv
= bpmp
->priv
;
266 mbox_free_channel(priv
->mbox
.channel
);
268 for (i
= 0; i
< bpmp
->threaded
.count
; i
++)
269 tegra186_bpmp_channel_cleanup(&bpmp
->threaded_channels
[i
]);
271 tegra186_bpmp_channel_cleanup(bpmp
->rx_channel
);
272 tegra186_bpmp_channel_cleanup(bpmp
->tx_channel
);
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);
278 static int tegra186_bpmp_resume(struct tegra_bpmp
*bpmp
)
282 /* reset message channels */
283 tegra186_bpmp_channel_reset(bpmp
->tx_channel
);
284 tegra186_bpmp_channel_reset(bpmp
->rx_channel
);
286 for (i
= 0; i
< bpmp
->threaded
.count
; i
++)
287 tegra186_bpmp_channel_reset(&bpmp
->threaded_channels
[i
]);
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
,