brintos

brintos / linux-shallow public Read only

0
0
Text · 4.4 KiB · 834aecd Raw
185 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2016 BayLibre SAS.4 * Author: Neil Armstrong <narmstrong@baylibre.com>5 * Synchronised with arm_mhu.c from :6 * Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd.7 * Copyright (C) 2015 Linaro Ltd.8 * Author: Jassi Brar <jaswinder.singh@linaro.org>9 */10 11#include <linux/interrupt.h>12#include <linux/spinlock.h>13#include <linux/mutex.h>14#include <linux/delay.h>15#include <linux/slab.h>16#include <linux/err.h>17#include <linux/io.h>18#include <linux/mod_devicetable.h>19#include <linux/module.h>20#include <linux/platform_device.h>21#include <linux/mailbox_controller.h>22 23#define INTR_SET_OFS	0x024#define INTR_STAT_OFS	0x425#define INTR_CLR_OFS	0x826 27#define MHU_SEC_OFFSET	0x028#define MHU_LP_OFFSET	0xc29#define MHU_HP_OFFSET	0x1830#define TX_REG_OFFSET	0x2431 32#define MHU_CHANS	333 34struct platform_mhu_link {35	int irq;36	void __iomem *tx_reg;37	void __iomem *rx_reg;38};39 40struct platform_mhu {41	void __iomem *base;42	struct platform_mhu_link mlink[MHU_CHANS];43	struct mbox_chan chan[MHU_CHANS];44	struct mbox_controller mbox;45};46 47static irqreturn_t platform_mhu_rx_interrupt(int irq, void *p)48{49	struct mbox_chan *chan = p;50	struct platform_mhu_link *mlink = chan->con_priv;51	u32 val;52 53	val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS);54	if (!val)55		return IRQ_NONE;56 57	mbox_chan_received_data(chan, (void *)&val);58 59	writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS);60 61	return IRQ_HANDLED;62}63 64static bool platform_mhu_last_tx_done(struct mbox_chan *chan)65{66	struct platform_mhu_link *mlink = chan->con_priv;67	u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);68 69	return (val == 0);70}71 72static int platform_mhu_send_data(struct mbox_chan *chan, void *data)73{74	struct platform_mhu_link *mlink = chan->con_priv;75	u32 *arg = data;76 77	writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS);78 79	return 0;80}81 82static int platform_mhu_startup(struct mbox_chan *chan)83{84	struct platform_mhu_link *mlink = chan->con_priv;85	u32 val;86	int ret;87 88	val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);89	writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS);90 91	ret = request_irq(mlink->irq, platform_mhu_rx_interrupt,92			  IRQF_SHARED, "platform_mhu_link", chan);93	if (ret) {94		dev_err(chan->mbox->dev,95			"Unable to acquire IRQ %d\n", mlink->irq);96		return ret;97	}98 99	return 0;100}101 102static void platform_mhu_shutdown(struct mbox_chan *chan)103{104	struct platform_mhu_link *mlink = chan->con_priv;105 106	free_irq(mlink->irq, chan);107}108 109static const struct mbox_chan_ops platform_mhu_ops = {110	.send_data = platform_mhu_send_data,111	.startup = platform_mhu_startup,112	.shutdown = platform_mhu_shutdown,113	.last_tx_done = platform_mhu_last_tx_done,114};115 116static int platform_mhu_probe(struct platform_device *pdev)117{118	int i, err;119	struct platform_mhu *mhu;120	struct device *dev = &pdev->dev;121	int platform_mhu_reg[MHU_CHANS] = {122		MHU_SEC_OFFSET, MHU_LP_OFFSET, MHU_HP_OFFSET123	};124 125	/* Allocate memory for device */126	mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL);127	if (!mhu)128		return -ENOMEM;129 130	mhu->base = devm_platform_ioremap_resource(pdev, 0);131	if (IS_ERR(mhu->base)) {132		dev_err(dev, "ioremap failed\n");133		return PTR_ERR(mhu->base);134	}135 136	for (i = 0; i < MHU_CHANS; i++) {137		mhu->chan[i].con_priv = &mhu->mlink[i];138		mhu->mlink[i].irq = platform_get_irq(pdev, i);139		if (mhu->mlink[i].irq < 0)140			return mhu->mlink[i].irq;141		mhu->mlink[i].rx_reg = mhu->base + platform_mhu_reg[i];142		mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET;143	}144 145	mhu->mbox.dev = dev;146	mhu->mbox.chans = &mhu->chan[0];147	mhu->mbox.num_chans = MHU_CHANS;148	mhu->mbox.ops = &platform_mhu_ops;149	mhu->mbox.txdone_irq = false;150	mhu->mbox.txdone_poll = true;151	mhu->mbox.txpoll_period = 1;152 153	platform_set_drvdata(pdev, mhu);154 155	err = devm_mbox_controller_register(dev, &mhu->mbox);156	if (err) {157		dev_err(dev, "Failed to register mailboxes %d\n", err);158		return err;159	}160 161	dev_info(dev, "Platform MHU Mailbox registered\n");162	return 0;163}164 165static const struct of_device_id platform_mhu_dt_ids[] = {166	{ .compatible = "amlogic,meson-gxbb-mhu", },167	{ /* sentinel */ },168};169MODULE_DEVICE_TABLE(of, platform_mhu_dt_ids);170 171static struct platform_driver platform_mhu_driver = {172	.probe	= platform_mhu_probe,173	.driver = {174		.name = "platform-mhu",175		.of_match_table	= platform_mhu_dt_ids,176	},177};178 179module_platform_driver(platform_mhu_driver);180 181MODULE_LICENSE("GPL v2");182MODULE_ALIAS("platform:platform-mhu");183MODULE_DESCRIPTION("Platform MHU Driver");184MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");185