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

mailbox-mpfs.c (6413B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Microchip PolarFire SoC (MPFS) system controller/mailbox controller driver
      4 *
      5 * Copyright (c) 2020 Microchip Corporation. All rights reserved.
      6 *
      7 * Author: Conor Dooley <conor.dooley@microchip.com>
      8 *
      9 */
     10
     11#include <linux/io.h>
     12#include <linux/err.h>
     13#include <linux/init.h>
     14#include <linux/module.h>
     15#include <linux/kernel.h>
     16#include <linux/interrupt.h>
     17#include <linux/platform_device.h>
     18#include <linux/mailbox_controller.h>
     19#include <soc/microchip/mpfs.h>
     20
     21#define SERVICES_CR_OFFSET		0x50u
     22#define SERVICES_SR_OFFSET		0x54u
     23#define MAILBOX_REG_OFFSET		0x800u
     24#define MSS_SYS_MAILBOX_DATA_OFFSET	0u
     25#define SCB_MASK_WIDTH			16u
     26
     27/* SCBCTRL service control register */
     28
     29#define SCB_CTRL_REQ (0)
     30#define SCB_CTRL_REQ_MASK BIT(SCB_CTRL_REQ)
     31
     32#define SCB_CTRL_BUSY (1)
     33#define SCB_CTRL_BUSY_MASK BIT(SCB_CTRL_BUSY)
     34
     35#define SCB_CTRL_ABORT (2)
     36#define SCB_CTRL_ABORT_MASK BIT(SCB_CTRL_ABORT)
     37
     38#define SCB_CTRL_NOTIFY (3)
     39#define SCB_CTRL_NOTIFY_MASK BIT(SCB_CTRL_NOTIFY)
     40
     41#define SCB_CTRL_POS (16)
     42#define SCB_CTRL_MASK GENMASK_ULL(SCB_CTRL_POS + SCB_MASK_WIDTH, SCB_CTRL_POS)
     43
     44/* SCBCTRL service status register */
     45
     46#define SCB_STATUS_REQ (0)
     47#define SCB_STATUS_REQ_MASK BIT(SCB_STATUS_REQ)
     48
     49#define SCB_STATUS_BUSY (1)
     50#define SCB_STATUS_BUSY_MASK BIT(SCB_STATUS_BUSY)
     51
     52#define SCB_STATUS_ABORT (2)
     53#define SCB_STATUS_ABORT_MASK BIT(SCB_STATUS_ABORT)
     54
     55#define SCB_STATUS_NOTIFY (3)
     56#define SCB_STATUS_NOTIFY_MASK BIT(SCB_STATUS_NOTIFY)
     57
     58#define SCB_STATUS_POS (16)
     59#define SCB_STATUS_MASK GENMASK_ULL(SCB_STATUS_POS + SCB_MASK_WIDTH, SCB_STATUS_POS)
     60
     61struct mpfs_mbox {
     62	struct mbox_controller controller;
     63	struct device *dev;
     64	int irq;
     65	void __iomem *mbox_base;
     66	void __iomem *int_reg;
     67	struct mbox_chan chans[1];
     68	struct mpfs_mss_response *response;
     69	u16 resp_offset;
     70};
     71
     72static bool mpfs_mbox_busy(struct mpfs_mbox *mbox)
     73{
     74	u32 status;
     75
     76	status = readl_relaxed(mbox->mbox_base + SERVICES_SR_OFFSET);
     77
     78	return status & SCB_STATUS_BUSY_MASK;
     79}
     80
     81static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data)
     82{
     83	struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
     84	struct mpfs_mss_msg *msg = data;
     85	u32 tx_trigger;
     86	u16 opt_sel;
     87	u32 val = 0u;
     88
     89	mbox->response = msg->response;
     90	mbox->resp_offset = msg->resp_offset;
     91
     92	if (mpfs_mbox_busy(mbox))
     93		return -EBUSY;
     94
     95	if (msg->cmd_data_size) {
     96		u32 index;
     97		u8 extra_bits = msg->cmd_data_size & 3;
     98		u32 *word_buf = (u32 *)msg->cmd_data;
     99
    100		for (index = 0; index < (msg->cmd_data_size / 4); index++)
    101			writel_relaxed(word_buf[index],
    102				       mbox->mbox_base + MAILBOX_REG_OFFSET + index * 0x4);
    103		if (extra_bits) {
    104			u8 i;
    105			u8 byte_off = ALIGN_DOWN(msg->cmd_data_size, 4);
    106			u8 *byte_buf = msg->cmd_data + byte_off;
    107
    108			val = readl_relaxed(mbox->mbox_base +
    109					    MAILBOX_REG_OFFSET + index * 0x4);
    110
    111			for (i = 0u; i < extra_bits; i++) {
    112				val &= ~(0xffu << (i * 8u));
    113				val |= (byte_buf[i] << (i * 8u));
    114			}
    115
    116			writel_relaxed(val,
    117				       mbox->mbox_base + MAILBOX_REG_OFFSET + index * 0x4);
    118		}
    119	}
    120
    121	opt_sel = ((msg->mbox_offset << 7u) | (msg->cmd_opcode & 0x7fu));
    122	tx_trigger = (opt_sel << SCB_CTRL_POS) & SCB_CTRL_MASK;
    123	tx_trigger |= SCB_CTRL_REQ_MASK | SCB_STATUS_NOTIFY_MASK;
    124	writel_relaxed(tx_trigger, mbox->mbox_base + SERVICES_CR_OFFSET);
    125
    126	return 0;
    127}
    128
    129static void mpfs_mbox_rx_data(struct mbox_chan *chan)
    130{
    131	struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
    132	struct mpfs_mss_response *response = mbox->response;
    133	u16 num_words = ALIGN((response->resp_size), (4)) / 4U;
    134	u32 i;
    135
    136	if (!response->resp_msg) {
    137		dev_err(mbox->dev, "failed to assign memory for response %d\n", -ENOMEM);
    138		return;
    139	}
    140
    141	if (!mpfs_mbox_busy(mbox)) {
    142		for (i = 0; i < num_words; i++) {
    143			response->resp_msg[i] =
    144				readl_relaxed(mbox->mbox_base + MAILBOX_REG_OFFSET
    145					      + mbox->resp_offset + i * 0x4);
    146		}
    147	}
    148
    149	mbox_chan_received_data(chan, response);
    150}
    151
    152static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data)
    153{
    154	struct mbox_chan *chan = data;
    155	struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
    156
    157	writel_relaxed(0, mbox->int_reg);
    158
    159	mpfs_mbox_rx_data(chan);
    160
    161	mbox_chan_txdone(chan, 0);
    162	return IRQ_HANDLED;
    163}
    164
    165static int mpfs_mbox_startup(struct mbox_chan *chan)
    166{
    167	struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
    168	int ret = 0;
    169
    170	if (!mbox)
    171		return -EINVAL;
    172
    173	ret = devm_request_irq(mbox->dev, mbox->irq, mpfs_mbox_inbox_isr, 0, "mpfs-mailbox", chan);
    174	if (ret)
    175		dev_err(mbox->dev, "failed to register mailbox interrupt:%d\n", ret);
    176
    177	return ret;
    178}
    179
    180static void mpfs_mbox_shutdown(struct mbox_chan *chan)
    181{
    182	struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
    183
    184	devm_free_irq(mbox->dev, mbox->irq, chan);
    185}
    186
    187static const struct mbox_chan_ops mpfs_mbox_ops = {
    188	.send_data = mpfs_mbox_send_data,
    189	.startup = mpfs_mbox_startup,
    190	.shutdown = mpfs_mbox_shutdown,
    191};
    192
    193static int mpfs_mbox_probe(struct platform_device *pdev)
    194{
    195	struct mpfs_mbox *mbox;
    196	struct resource *regs;
    197	int ret;
    198
    199	mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
    200	if (!mbox)
    201		return -ENOMEM;
    202
    203	mbox->mbox_base = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
    204	if (IS_ERR(mbox->mbox_base))
    205		return PTR_ERR(mbox->mbox_base);
    206
    207	mbox->int_reg = devm_platform_get_and_ioremap_resource(pdev, 1, &regs);
    208	if (IS_ERR(mbox->int_reg))
    209		return PTR_ERR(mbox->int_reg);
    210
    211	mbox->irq = platform_get_irq(pdev, 0);
    212	if (mbox->irq < 0)
    213		return mbox->irq;
    214
    215	mbox->dev = &pdev->dev;
    216
    217	mbox->chans[0].con_priv = mbox;
    218	mbox->controller.dev = mbox->dev;
    219	mbox->controller.num_chans = 1;
    220	mbox->controller.chans = mbox->chans;
    221	mbox->controller.ops = &mpfs_mbox_ops;
    222	mbox->controller.txdone_irq = true;
    223
    224	ret = devm_mbox_controller_register(&pdev->dev, &mbox->controller);
    225	if (ret) {
    226		dev_err(&pdev->dev, "Registering MPFS mailbox controller failed\n");
    227		return ret;
    228	}
    229	dev_info(&pdev->dev, "Registered MPFS mailbox controller driver\n");
    230
    231	return 0;
    232}
    233
    234static const struct of_device_id mpfs_mbox_of_match[] = {
    235	{.compatible = "microchip,mpfs-mailbox", },
    236	{},
    237};
    238MODULE_DEVICE_TABLE(of, mpfs_mbox_of_match);
    239
    240static struct platform_driver mpfs_mbox_driver = {
    241	.driver = {
    242		.name = "mpfs-mailbox",
    243		.of_match_table = mpfs_mbox_of_match,
    244	},
    245	.probe = mpfs_mbox_probe,
    246};
    247module_platform_driver(mpfs_mbox_driver);
    248
    249MODULE_LICENSE("GPL v2");
    250MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
    251MODULE_DESCRIPTION("MPFS mailbox controller driver");