cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

armada-37xx-rwtm-mailbox.c (5178B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * rWTM BIU Mailbox driver for Armada 37xx
      4 *
      5 * Author: Marek BehĂșn <kabel@kernel.org>
      6 */
      7
      8#include <linux/device.h>
      9#include <linux/interrupt.h>
     10#include <linux/io.h>
     11#include <linux/kernel.h>
     12#include <linux/mailbox_controller.h>
     13#include <linux/module.h>
     14#include <linux/of.h>
     15#include <linux/platform_device.h>
     16#include <linux/armada-37xx-rwtm-mailbox.h>
     17
     18#define DRIVER_NAME	"armada-37xx-rwtm-mailbox"
     19
     20/* relative to rWTM BIU Mailbox Registers */
     21#define RWTM_MBOX_PARAM(i)		(0x0 + ((i) << 2))
     22#define RWTM_MBOX_COMMAND		0x40
     23#define RWTM_MBOX_RETURN_STATUS		0x80
     24#define RWTM_MBOX_STATUS(i)		(0x84 + ((i) << 2))
     25#define RWTM_MBOX_FIFO_STATUS		0xc4
     26#define FIFO_STS_RDY			0x100
     27#define FIFO_STS_CNTR_MASK		0x7
     28#define FIFO_STS_CNTR_MAX		4
     29
     30#define RWTM_HOST_INT_RESET		0xc8
     31#define RWTM_HOST_INT_MASK		0xcc
     32#define SP_CMD_COMPLETE			BIT(0)
     33#define SP_CMD_QUEUE_FULL_ACCESS	BIT(17)
     34#define SP_CMD_QUEUE_FULL		BIT(18)
     35
     36struct a37xx_mbox {
     37	struct device *dev;
     38	struct mbox_controller controller;
     39	void __iomem *base;
     40	int irq;
     41};
     42
     43static void a37xx_mbox_receive(struct mbox_chan *chan)
     44{
     45	struct a37xx_mbox *mbox = chan->con_priv;
     46	struct armada_37xx_rwtm_rx_msg rx_msg;
     47	int i;
     48
     49	rx_msg.retval = readl(mbox->base + RWTM_MBOX_RETURN_STATUS);
     50	for (i = 0; i < 16; ++i)
     51		rx_msg.status[i] = readl(mbox->base + RWTM_MBOX_STATUS(i));
     52
     53	mbox_chan_received_data(chan, &rx_msg);
     54}
     55
     56static irqreturn_t a37xx_mbox_irq_handler(int irq, void *data)
     57{
     58	struct mbox_chan *chan = data;
     59	struct a37xx_mbox *mbox = chan->con_priv;
     60	u32 reg;
     61
     62	reg = readl(mbox->base + RWTM_HOST_INT_RESET);
     63
     64	if (reg & SP_CMD_COMPLETE)
     65		a37xx_mbox_receive(chan);
     66
     67	if (reg & (SP_CMD_QUEUE_FULL_ACCESS | SP_CMD_QUEUE_FULL))
     68		dev_err(mbox->dev, "Secure processor command queue full\n");
     69
     70	writel(reg, mbox->base + RWTM_HOST_INT_RESET);
     71	if (reg)
     72		mbox_chan_txdone(chan, 0);
     73
     74	return reg ? IRQ_HANDLED : IRQ_NONE;
     75}
     76
     77static int a37xx_mbox_send_data(struct mbox_chan *chan, void *data)
     78{
     79	struct a37xx_mbox *mbox = chan->con_priv;
     80	struct armada_37xx_rwtm_tx_msg *msg = data;
     81	int i;
     82	u32 reg;
     83
     84	if (!data)
     85		return -EINVAL;
     86
     87	reg = readl(mbox->base + RWTM_MBOX_FIFO_STATUS);
     88	if (!(reg & FIFO_STS_RDY))
     89		dev_warn(mbox->dev, "Secure processor not ready\n");
     90
     91	if ((reg & FIFO_STS_CNTR_MASK) >= FIFO_STS_CNTR_MAX) {
     92		dev_err(mbox->dev, "Secure processor command queue full\n");
     93		return -EBUSY;
     94	}
     95
     96	for (i = 0; i < 16; ++i)
     97		writel(msg->args[i], mbox->base + RWTM_MBOX_PARAM(i));
     98	writel(msg->command, mbox->base + RWTM_MBOX_COMMAND);
     99
    100	return 0;
    101}
    102
    103static int a37xx_mbox_startup(struct mbox_chan *chan)
    104{
    105	struct a37xx_mbox *mbox = chan->con_priv;
    106	u32 reg;
    107	int ret;
    108
    109	ret = devm_request_irq(mbox->dev, mbox->irq, a37xx_mbox_irq_handler, 0,
    110			       DRIVER_NAME, chan);
    111	if (ret < 0) {
    112		dev_err(mbox->dev, "Cannot request irq\n");
    113		return ret;
    114	}
    115
    116	/* enable IRQ generation */
    117	reg = readl(mbox->base + RWTM_HOST_INT_MASK);
    118	reg &= ~(SP_CMD_COMPLETE | SP_CMD_QUEUE_FULL_ACCESS | SP_CMD_QUEUE_FULL);
    119	writel(reg, mbox->base + RWTM_HOST_INT_MASK);
    120
    121	return 0;
    122}
    123
    124static void a37xx_mbox_shutdown(struct mbox_chan *chan)
    125{
    126	u32 reg;
    127	struct a37xx_mbox *mbox = chan->con_priv;
    128
    129	/* disable interrupt generation */
    130	reg = readl(mbox->base + RWTM_HOST_INT_MASK);
    131	reg |= SP_CMD_COMPLETE | SP_CMD_QUEUE_FULL_ACCESS | SP_CMD_QUEUE_FULL;
    132	writel(reg, mbox->base + RWTM_HOST_INT_MASK);
    133
    134	devm_free_irq(mbox->dev, mbox->irq, chan);
    135}
    136
    137static const struct mbox_chan_ops a37xx_mbox_ops = {
    138	.send_data	= a37xx_mbox_send_data,
    139	.startup	= a37xx_mbox_startup,
    140	.shutdown	= a37xx_mbox_shutdown,
    141};
    142
    143static int armada_37xx_mbox_probe(struct platform_device *pdev)
    144{
    145	struct a37xx_mbox *mbox;
    146	struct mbox_chan *chans;
    147	int ret;
    148
    149	mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
    150	if (!mbox)
    151		return -ENOMEM;
    152
    153	/* Allocated one channel */
    154	chans = devm_kzalloc(&pdev->dev, sizeof(*chans), GFP_KERNEL);
    155	if (!chans)
    156		return -ENOMEM;
    157
    158	mbox->base = devm_platform_ioremap_resource(pdev, 0);
    159	if (IS_ERR(mbox->base))
    160		return PTR_ERR(mbox->base);
    161
    162	mbox->irq = platform_get_irq(pdev, 0);
    163	if (mbox->irq < 0)
    164		return mbox->irq;
    165
    166	mbox->dev = &pdev->dev;
    167
    168	/* Hardware supports only one channel. */
    169	chans[0].con_priv = mbox;
    170	mbox->controller.dev = mbox->dev;
    171	mbox->controller.num_chans = 1;
    172	mbox->controller.chans = chans;
    173	mbox->controller.ops = &a37xx_mbox_ops;
    174	mbox->controller.txdone_irq = true;
    175
    176	ret = devm_mbox_controller_register(mbox->dev, &mbox->controller);
    177	if (ret) {
    178		dev_err(&pdev->dev, "Could not register mailbox controller\n");
    179		return ret;
    180	}
    181
    182	platform_set_drvdata(pdev, mbox);
    183	return ret;
    184}
    185
    186
    187static const struct of_device_id armada_37xx_mbox_match[] = {
    188	{ .compatible = "marvell,armada-3700-rwtm-mailbox" },
    189	{ },
    190};
    191
    192MODULE_DEVICE_TABLE(of, armada_37xx_mbox_match);
    193
    194static struct platform_driver armada_37xx_mbox_driver = {
    195	.probe	= armada_37xx_mbox_probe,
    196	.driver	= {
    197		.name		= DRIVER_NAME,
    198		.of_match_table	= armada_37xx_mbox_match,
    199	},
    200};
    201
    202module_platform_driver(armada_37xx_mbox_driver);
    203
    204MODULE_LICENSE("GPL v2");
    205MODULE_DESCRIPTION("rWTM BIU Mailbox driver for Armada 37xx");
    206MODULE_AUTHOR("Marek Behun <kabel@kernel.org>");