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