brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 6295f56 Raw
238 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2018, NVIDIA CORPORATION.4 */5 6#include <linux/interrupt.h>7#include <linux/irq.h>8#include <linux/io.h>9#include <linux/of.h>10#include <linux/platform_device.h>11 12#include <soc/tegra/bpmp.h>13 14#include "bpmp-private.h"15 16#define TRIGGER_OFFSET		0x00017#define RESULT_OFFSET(id)	(0xc00 + id * 4)18#define TRIGGER_ID_SHIFT	1619#define TRIGGER_CMD_GET		420 21#define STA_OFFSET		022#define SET_OFFSET		423#define CLR_OFFSET		824 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))30 31struct tegra210_bpmp {32	void __iomem *atomics;33	void __iomem *arb_sema;34	struct irq_data *tx_irq_data;35};36 37static u32 bpmp_channel_status(struct tegra_bpmp *bpmp, unsigned int index)38{39	struct tegra210_bpmp *priv = bpmp->priv;40 41	return __raw_readl(priv->arb_sema + STA_OFFSET) & CH_MASK(index);42}43 44static bool tegra210_bpmp_is_response_ready(struct tegra_bpmp_channel *channel)45{46	unsigned int index = channel->index;47 48	return bpmp_channel_status(channel->bpmp, index) == MA_ACKD(index);49}50 51static bool tegra210_bpmp_is_request_ready(struct tegra_bpmp_channel *channel)52{53	unsigned int index = channel->index;54 55	return bpmp_channel_status(channel->bpmp, index) == SL_SIGL(index);56}57 58static bool59tegra210_bpmp_is_request_channel_free(struct tegra_bpmp_channel *channel)60{61	unsigned int index = channel->index;62 63	return bpmp_channel_status(channel->bpmp, index) == MA_FREE(index);64}65 66static bool67tegra210_bpmp_is_response_channel_free(struct tegra_bpmp_channel *channel)68{69	unsigned int index = channel->index;70 71	return bpmp_channel_status(channel->bpmp, index) == SL_QUED(index);72}73 74static int tegra210_bpmp_post_request(struct tegra_bpmp_channel *channel)75{76	struct tegra210_bpmp *priv = channel->bpmp->priv;77 78	__raw_writel(CH_MASK(channel->index), priv->arb_sema + CLR_OFFSET);79 80	return 0;81}82 83static int tegra210_bpmp_post_response(struct tegra_bpmp_channel *channel)84{85	struct tegra210_bpmp *priv = channel->bpmp->priv;86 87	__raw_writel(MA_ACKD(channel->index), priv->arb_sema + SET_OFFSET);88 89	return 0;90}91 92static int tegra210_bpmp_ack_response(struct tegra_bpmp_channel *channel)93{94	struct tegra210_bpmp *priv = channel->bpmp->priv;95 96	__raw_writel(MA_ACKD(channel->index) ^ MA_FREE(channel->index),97		     priv->arb_sema + CLR_OFFSET);98 99	return 0;100}101 102static int tegra210_bpmp_ack_request(struct tegra_bpmp_channel *channel)103{104	struct tegra210_bpmp *priv = channel->bpmp->priv;105 106	__raw_writel(SL_QUED(channel->index), priv->arb_sema + SET_OFFSET);107 108	return 0;109}110 111static int tegra210_bpmp_ring_doorbell(struct tegra_bpmp *bpmp)112{113	struct tegra210_bpmp *priv = bpmp->priv;114	struct irq_data *irq_data = priv->tx_irq_data;115 116	/*117	 * Tegra Legacy Interrupt Controller (LIC) is used to notify BPMP of118	 * available messages119	 */120	if (irq_data->chip->irq_retrigger)121		return irq_data->chip->irq_retrigger(irq_data);122 123	return -EINVAL;124}125 126static irqreturn_t rx_irq(int irq, void *data)127{128	struct tegra_bpmp *bpmp = data;129 130	tegra_bpmp_handle_rx(bpmp);131 132	return IRQ_HANDLED;133}134 135static int tegra210_bpmp_channel_init(struct tegra_bpmp_channel *channel,136				      struct tegra_bpmp *bpmp,137				      unsigned int index)138{139	struct tegra210_bpmp *priv = bpmp->priv;140	void __iomem *p;141	u32 address;142 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));147 148	p = devm_ioremap(bpmp->dev, address, 0x80);149	if (!p)150		return -ENOMEM;151 152	iosys_map_set_vaddr_iomem(&channel->ib, p);153	iosys_map_set_vaddr_iomem(&channel->ob, p);154 155	channel->index = index;156	init_completion(&channel->completion);157	channel->bpmp = bpmp;158 159	return 0;160}161 162static int tegra210_bpmp_init(struct tegra_bpmp *bpmp)163{164	struct platform_device *pdev = to_platform_device(bpmp->dev);165	struct tegra210_bpmp *priv;166	unsigned int i;167	int err;168 169	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);170	if (!priv)171		return -ENOMEM;172 173	bpmp->priv = priv;174 175	priv->atomics = devm_platform_ioremap_resource(pdev, 0);176	if (IS_ERR(priv->atomics))177		return PTR_ERR(priv->atomics);178 179	priv->arb_sema = devm_platform_ioremap_resource(pdev, 1);180	if (IS_ERR(priv->arb_sema))181		return PTR_ERR(priv->arb_sema);182 183	err = tegra210_bpmp_channel_init(bpmp->tx_channel, bpmp,184					 bpmp->soc->channels.cpu_tx.offset);185	if (err < 0)186		return err;187 188	err = tegra210_bpmp_channel_init(bpmp->rx_channel, bpmp,189					 bpmp->soc->channels.cpu_rx.offset);190	if (err < 0)191		return err;192 193	for (i = 0; i < bpmp->threaded.count; i++) {194		unsigned int index = bpmp->soc->channels.thread.offset + i;195 196		err = tegra210_bpmp_channel_init(&bpmp->threaded_channels[i],197						 bpmp, index);198		if (err < 0)199			return err;200	}201 202	err = platform_get_irq_byname(pdev, "tx");203	if (err < 0)204		return err;205 206	priv->tx_irq_data = irq_get_irq_data(err);207	if (!priv->tx_irq_data) {208		dev_err(&pdev->dev, "failed to get IRQ data for TX IRQ\n");209		return -ENOENT;210	}211 212	err = platform_get_irq_byname(pdev, "rx");213	if (err < 0)214		return err;215 216	err = devm_request_irq(&pdev->dev, err, rx_irq,217			       IRQF_NO_SUSPEND, dev_name(&pdev->dev), bpmp);218	if (err < 0) {219		dev_err(&pdev->dev, "failed to request IRQ: %d\n", err);220		return err;221	}222 223	return 0;224}225 226const struct tegra_bpmp_ops tegra210_bpmp_ops = {227	.init = tegra210_bpmp_init,228	.is_response_ready = tegra210_bpmp_is_response_ready,229	.is_request_ready = tegra210_bpmp_is_request_ready,230	.ack_response = tegra210_bpmp_ack_response,231	.ack_request = tegra210_bpmp_ack_request,232	.is_response_channel_free = tegra210_bpmp_is_response_channel_free,233	.is_request_channel_free = tegra210_bpmp_is_request_channel_free,234	.post_response = tegra210_bpmp_post_response,235	.post_request = tegra210_bpmp_post_request,236	.ring_doorbell = tegra210_bpmp_ring_doorbell,237};238