1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018, NVIDIA CORPORATION.
6 #include <linux/interrupt.h>
10 #include <linux/platform_device.h>
12 #include <soc/tegra/bpmp.h>
14 #include "bpmp-private.h"
16 #define TRIGGER_OFFSET 0x000
17 #define RESULT_OFFSET(id) (0xc00 + id * 4)
18 #define TRIGGER_ID_SHIFT 16
19 #define TRIGGER_CMD_GET 4
25 #define CH_MASK(ch) (0x3 << ((ch) * 2))
26 #define SL_SIGL(ch) (0x0 << ((ch) * 2))
27 #define SL_QUED(ch) (0x1 << ((ch) * 2))
28 #define MA_FREE(ch) (0x2 << ((ch) * 2))
29 #define MA_ACKD(ch) (0x3 << ((ch) * 2))
31 struct tegra210_bpmp
{
32 void __iomem
*atomics
;
33 void __iomem
*arb_sema
;
34 struct irq_data
*tx_irq_data
;
37 static u32
bpmp_channel_status(struct tegra_bpmp
*bpmp
, unsigned int index
)
39 struct tegra210_bpmp
*priv
= bpmp
->priv
;
41 return __raw_readl(priv
->arb_sema
+ STA_OFFSET
) & CH_MASK(index
);
44 static bool tegra210_bpmp_is_response_ready(struct tegra_bpmp_channel
*channel
)
46 unsigned int index
= channel
->index
;
48 return bpmp_channel_status(channel
->bpmp
, index
) == MA_ACKD(index
);
51 static bool tegra210_bpmp_is_request_ready(struct tegra_bpmp_channel
*channel
)
53 unsigned int index
= channel
->index
;
55 return bpmp_channel_status(channel
->bpmp
, index
) == SL_SIGL(index
);
59 tegra210_bpmp_is_request_channel_free(struct tegra_bpmp_channel
*channel
)
61 unsigned int index
= channel
->index
;
63 return bpmp_channel_status(channel
->bpmp
, index
) == MA_FREE(index
);
67 tegra210_bpmp_is_response_channel_free(struct tegra_bpmp_channel
*channel
)
69 unsigned int index
= channel
->index
;
71 return bpmp_channel_status(channel
->bpmp
, index
) == SL_QUED(index
);
74 static int tegra210_bpmp_post_request(struct tegra_bpmp_channel
*channel
)
76 struct tegra210_bpmp
*priv
= channel
->bpmp
->priv
;
78 __raw_writel(CH_MASK(channel
->index
), priv
->arb_sema
+ CLR_OFFSET
);
83 static int tegra210_bpmp_post_response(struct tegra_bpmp_channel
*channel
)
85 struct tegra210_bpmp
*priv
= channel
->bpmp
->priv
;
87 __raw_writel(MA_ACKD(channel
->index
), priv
->arb_sema
+ SET_OFFSET
);
92 static int tegra210_bpmp_ack_response(struct tegra_bpmp_channel
*channel
)
94 struct tegra210_bpmp
*priv
= channel
->bpmp
->priv
;
96 __raw_writel(MA_ACKD(channel
->index
) ^ MA_FREE(channel
->index
),
97 priv
->arb_sema
+ CLR_OFFSET
);
102 static int tegra210_bpmp_ack_request(struct tegra_bpmp_channel
*channel
)
104 struct tegra210_bpmp
*priv
= channel
->bpmp
->priv
;
106 __raw_writel(SL_QUED(channel
->index
), priv
->arb_sema
+ SET_OFFSET
);
111 static int tegra210_bpmp_ring_doorbell(struct tegra_bpmp
*bpmp
)
113 struct tegra210_bpmp
*priv
= bpmp
->priv
;
114 struct irq_data
*irq_data
= priv
->tx_irq_data
;
117 * Tegra Legacy Interrupt Controller (LIC) is used to notify BPMP of
120 if (irq_data
->chip
->irq_retrigger
)
121 return irq_data
->chip
->irq_retrigger(irq_data
);
126 static irqreturn_t
rx_irq(int irq
, void *data
)
128 struct tegra_bpmp
*bpmp
= data
;
130 tegra_bpmp_handle_rx(bpmp
);
135 static int tegra210_bpmp_channel_init(struct tegra_bpmp_channel
*channel
,
136 struct tegra_bpmp
*bpmp
,
139 struct tegra210_bpmp
*priv
= bpmp
->priv
;
143 /* Retrieve channel base address from BPMP */
144 writel(index
<< TRIGGER_ID_SHIFT
| TRIGGER_CMD_GET
,
145 priv
->atomics
+ TRIGGER_OFFSET
);
146 address
= readl(priv
->atomics
+ RESULT_OFFSET(index
));
148 p
= devm_ioremap(bpmp
->dev
, address
, 0x80);
154 channel
->index
= index
;
155 init_completion(&channel
->completion
);
156 channel
->bpmp
= bpmp
;
161 static int tegra210_bpmp_init(struct tegra_bpmp
*bpmp
)
163 struct platform_device
*pdev
= to_platform_device(bpmp
->dev
);
164 struct tegra210_bpmp
*priv
;
165 struct resource
*res
;
169 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
175 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
176 priv
->atomics
= devm_ioremap_resource(&pdev
->dev
, res
);
177 if (IS_ERR(priv
->atomics
))
178 return PTR_ERR(priv
->atomics
);
180 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 1);
181 priv
->arb_sema
= devm_ioremap_resource(&pdev
->dev
, res
);
182 if (IS_ERR(priv
->arb_sema
))
183 return PTR_ERR(priv
->arb_sema
);
185 err
= tegra210_bpmp_channel_init(bpmp
->tx_channel
, bpmp
,
186 bpmp
->soc
->channels
.cpu_tx
.offset
);
190 err
= tegra210_bpmp_channel_init(bpmp
->rx_channel
, bpmp
,
191 bpmp
->soc
->channels
.cpu_rx
.offset
);
195 for (i
= 0; i
< bpmp
->threaded
.count
; i
++) {
196 unsigned int index
= bpmp
->soc
->channels
.thread
.offset
+ i
;
198 err
= tegra210_bpmp_channel_init(&bpmp
->threaded_channels
[i
],
204 err
= platform_get_irq_byname(pdev
, "tx");
206 dev_err(&pdev
->dev
, "failed to get TX IRQ: %d\n", err
);
210 priv
->tx_irq_data
= irq_get_irq_data(err
);
211 if (!priv
->tx_irq_data
) {
212 dev_err(&pdev
->dev
, "failed to get IRQ data for TX IRQ\n");
216 err
= platform_get_irq_byname(pdev
, "rx");
218 dev_err(&pdev
->dev
, "failed to get rx IRQ: %d\n", err
);
222 err
= devm_request_irq(&pdev
->dev
, err
, rx_irq
,
223 IRQF_NO_SUSPEND
, dev_name(&pdev
->dev
), bpmp
);
225 dev_err(&pdev
->dev
, "failed to request IRQ: %d\n", err
);
232 const struct tegra_bpmp_ops tegra210_bpmp_ops
= {
233 .init
= tegra210_bpmp_init
,
234 .is_response_ready
= tegra210_bpmp_is_response_ready
,
235 .is_request_ready
= tegra210_bpmp_is_request_ready
,
236 .ack_response
= tegra210_bpmp_ack_response
,
237 .ack_request
= tegra210_bpmp_ack_request
,
238 .is_response_channel_free
= tegra210_bpmp_is_response_channel_free
,
239 .is_request_channel_free
= tegra210_bpmp_is_request_channel_free
,
240 .post_response
= tegra210_bpmp_post_response
,
241 .post_request
= tegra210_bpmp_post_request
,
242 .ring_doorbell
= tegra210_bpmp_ring_doorbell
,