Skip to content

Commit 2abd484

Browse files
p2mate-nvthierryreding
authored andcommitted
firmware: tegra: bpmp: Add support for DRAM MRQ GSCs
Implement support for DRAM MRQ GSCs. Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> [treding@nvidia.com: drop unnecessary discrimination enum] Signed-off-by: Thierry Reding <treding@nvidia.com>
1 parent ac9a786 commit 2abd484

2 files changed

Lines changed: 147 additions & 61 deletions

File tree

drivers/firmware/tegra/bpmp-tegra186.c

Lines changed: 145 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
*/
55

66
#include <linux/genalloc.h>
7+
#include <linux/io.h>
78
#include <linux/mailbox_client.h>
9+
#include <linux/of_address.h>
810
#include <linux/platform_device.h>
911

1012
#include <soc/tegra/bpmp.h>
@@ -18,7 +20,10 @@ struct tegra186_bpmp {
1820

1921
struct {
2022
struct gen_pool *pool;
21-
void __iomem *virt;
23+
union {
24+
void __iomem *sram;
25+
void *dram;
26+
};
2227
dma_addr_t phys;
2328
} tx, rx;
2429

@@ -118,8 +123,13 @@ static int tegra186_bpmp_channel_init(struct tegra_bpmp_channel *channel,
118123
queue_size = tegra_ivc_total_queue_size(message_size);
119124
offset = queue_size * index;
120125

121-
iosys_map_set_vaddr_iomem(&rx, priv->rx.virt + offset);
122-
iosys_map_set_vaddr_iomem(&tx, priv->tx.virt + offset);
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+
}
123133

124134
err = tegra_ivc_init(channel->ivc, NULL, &rx, priv->rx.phys + offset, &tx,
125135
priv->tx.phys + offset, 1, message_size, tegra186_bpmp_ivc_notify,
@@ -158,27 +168,82 @@ static void mbox_handle_rx(struct mbox_client *client, void *data)
158168
tegra_bpmp_handle_rx(bpmp);
159169
}
160170

161-
static int tegra186_bpmp_init(struct tegra_bpmp *bpmp)
171+
static void tegra186_bpmp_teardown_channels(struct tegra_bpmp *bpmp)
162172
{
163-
struct tegra186_bpmp *priv;
173+
struct tegra186_bpmp *priv = bpmp->priv;
164174
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+
192+
static 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;
165198
int err;
166199

167-
priv = devm_kzalloc(bpmp->dev, sizeof(*priv), GFP_KERNEL);
168-
if (!priv)
169-
return -ENOMEM;
200+
np = of_parse_phandle(bpmp->dev->of_node, "memory-region", 0);
201+
if (!np)
202+
return -ENODEV;
170203

171-
bpmp->priv = priv;
172-
priv->parent = bpmp;
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+
233+
static int tegra186_bpmp_sram_init(struct tegra_bpmp *bpmp)
234+
{
235+
struct tegra186_bpmp *priv = bpmp->priv;
236+
int err;
173237

174238
priv->tx.pool = of_gen_pool_get(bpmp->dev->of_node, "shmem", 0);
175239
if (!priv->tx.pool) {
176240
dev_err(bpmp->dev, "TX shmem pool not found\n");
177241
return -EPROBE_DEFER;
178242
}
179243

180-
priv->tx.virt = (void __iomem *)gen_pool_dma_alloc(priv->tx.pool, 4096, &priv->tx.phys);
181-
if (!priv->tx.virt) {
244+
priv->tx.sram = (void __iomem *)gen_pool_dma_alloc(priv->tx.pool, 4096,
245+
&priv->tx.phys);
246+
if (!priv->tx.sram) {
182247
dev_err(bpmp->dev, "failed to allocate from TX pool\n");
183248
return -ENOMEM;
184249
}
@@ -190,32 +255,89 @@ static int tegra186_bpmp_init(struct tegra_bpmp *bpmp)
190255
goto free_tx;
191256
}
192257

193-
priv->rx.virt = (void __iomem *)gen_pool_dma_alloc(priv->rx.pool, 4096, &priv->rx.phys);
194-
if (!priv->rx.virt) {
258+
priv->rx.sram = (void __iomem *)gen_pool_dma_alloc(priv->rx.pool, 4096,
259+
&priv->rx.phys);
260+
if (!priv->rx.sram) {
195261
dev_err(bpmp->dev, "failed to allocate from RX pool\n");
196262
err = -ENOMEM;
197263
goto free_tx;
198264
}
199265

266+
return 0;
267+
268+
free_tx:
269+
gen_pool_free(priv->tx.pool, (unsigned long)priv->tx.sram, 4096);
270+
271+
return err;
272+
}
273+
274+
static 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+
200286
err = tegra186_bpmp_channel_init(bpmp->tx_channel, bpmp,
201287
bpmp->soc->channels.cpu_tx.offset);
202288
if (err < 0)
203-
goto free_rx;
289+
return err;
204290

205291
err = tegra186_bpmp_channel_init(bpmp->rx_channel, bpmp,
206292
bpmp->soc->channels.cpu_rx.offset);
207-
if (err < 0)
208-
goto cleanup_tx_channel;
293+
if (err < 0) {
294+
tegra186_bpmp_channel_cleanup(bpmp->tx_channel);
295+
return err;
296+
}
209297

210298
for (i = 0; i < bpmp->threaded.count; i++) {
211299
unsigned int index = bpmp->soc->channels.thread.offset + i;
212300

213301
err = tegra186_bpmp_channel_init(&bpmp->threaded_channels[i],
214302
bpmp, index);
215303
if (err < 0)
216-
goto cleanup_channels;
304+
break;
217305
}
218306

307+
if (err < 0)
308+
tegra186_bpmp_teardown_channels(bpmp);
309+
310+
return err;
311+
}
312+
313+
static 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+
325+
static 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+
219341
/* mbox registration */
220342
priv->mbox.client.dev = bpmp->dev;
221343
priv->mbox.client.rx_callback = mbox_handle_rx;
@@ -226,63 +348,27 @@ static int tegra186_bpmp_init(struct tegra_bpmp *bpmp)
226348
if (IS_ERR(priv->mbox.channel)) {
227349
err = PTR_ERR(priv->mbox.channel);
228350
dev_err(bpmp->dev, "failed to get HSP mailbox: %d\n", err);
229-
goto cleanup_channels;
351+
tegra186_bpmp_teardown_channels(bpmp);
352+
return err;
230353
}
231354

232-
tegra186_bpmp_channel_reset(bpmp->tx_channel);
233-
tegra186_bpmp_channel_reset(bpmp->rx_channel);
234-
235-
for (i = 0; i < bpmp->threaded.count; i++)
236-
tegra186_bpmp_channel_reset(&bpmp->threaded_channels[i]);
355+
tegra186_bpmp_reset_channels(bpmp);
237356

238357
return 0;
239-
240-
cleanup_channels:
241-
for (i = 0; i < bpmp->threaded.count; i++) {
242-
if (!bpmp->threaded_channels[i].bpmp)
243-
continue;
244-
245-
tegra186_bpmp_channel_cleanup(&bpmp->threaded_channels[i]);
246-
}
247-
248-
tegra186_bpmp_channel_cleanup(bpmp->rx_channel);
249-
cleanup_tx_channel:
250-
tegra186_bpmp_channel_cleanup(bpmp->tx_channel);
251-
free_rx:
252-
gen_pool_free(priv->rx.pool, (unsigned long)priv->rx.virt, 4096);
253-
free_tx:
254-
gen_pool_free(priv->tx.pool, (unsigned long)priv->tx.virt, 4096);
255-
256-
return err;
257358
}
258359

259360
static void tegra186_bpmp_deinit(struct tegra_bpmp *bpmp)
260361
{
261362
struct tegra186_bpmp *priv = bpmp->priv;
262-
unsigned int i;
263363

264364
mbox_free_channel(priv->mbox.channel);
265365

266-
for (i = 0; i < bpmp->threaded.count; i++)
267-
tegra186_bpmp_channel_cleanup(&bpmp->threaded_channels[i]);
268-
269-
tegra186_bpmp_channel_cleanup(bpmp->rx_channel);
270-
tegra186_bpmp_channel_cleanup(bpmp->tx_channel);
271-
272-
gen_pool_free(priv->rx.pool, (unsigned long)priv->rx.virt, 4096);
273-
gen_pool_free(priv->tx.pool, (unsigned long)priv->tx.virt, 4096);
366+
tegra186_bpmp_teardown_channels(bpmp);
274367
}
275368

276369
static int tegra186_bpmp_resume(struct tegra_bpmp *bpmp)
277370
{
278-
unsigned int i;
279-
280-
/* reset message channels */
281-
tegra186_bpmp_channel_reset(bpmp->tx_channel);
282-
tegra186_bpmp_channel_reset(bpmp->rx_channel);
283-
284-
for (i = 0; i < bpmp->threaded.count; i++)
285-
tegra186_bpmp_channel_reset(&bpmp->threaded_channels[i]);
371+
tegra186_bpmp_reset_channels(bpmp);
286372

287373
return 0;
288374
}

drivers/firmware/tegra/bpmp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,8 @@ static int tegra_bpmp_probe(struct platform_device *pdev)
735735
if (!bpmp->threaded_channels)
736736
return -ENOMEM;
737737

738+
platform_set_drvdata(pdev, bpmp);
739+
738740
err = bpmp->soc->ops->init(bpmp);
739741
if (err < 0)
740742
return err;
@@ -758,8 +760,6 @@ static int tegra_bpmp_probe(struct platform_device *pdev)
758760

759761
dev_info(&pdev->dev, "firmware: %.*s\n", (int)sizeof(tag), tag);
760762

761-
platform_set_drvdata(pdev, bpmp);
762-
763763
err = of_platform_default_populate(pdev->dev.of_node, NULL, &pdev->dev);
764764
if (err < 0)
765765
goto free_mrq;

0 commit comments

Comments
 (0)