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>");