brintos

brintos / linux-shallow public Read only

0
0
Text · 5.1 KiB · 456a117 Raw
207 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * rWTM BIU Mailbox driver for Armada 37xx4 *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		0x4023#define RWTM_MBOX_RETURN_STATUS		0x8024#define RWTM_MBOX_STATUS(i)		(0x84 + ((i) << 2))25#define RWTM_MBOX_FIFO_STATUS		0xc426#define FIFO_STS_RDY			0x10027#define FIFO_STS_CNTR_MASK		0x728#define FIFO_STS_CNTR_MAX		429 30#define RWTM_HOST_INT_RESET		0xc831#define RWTM_HOST_INT_MASK		0xcc32#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>");207