brintos

brintos / linux-shallow public Read only

0
0
Text · 14.7 KiB · 6797770 Raw
615 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * OMAP mailbox driver4 *5 * Copyright (C) 2006-2009 Nokia Corporation. All rights reserved.6 * Copyright (C) 2013-2021 Texas Instruments Incorporated - https://www.ti.com7 *8 * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>9 *          Suman Anna <s-anna@ti.com>10 */11 12#include <linux/interrupt.h>13#include <linux/spinlock.h>14#include <linux/mutex.h>15#include <linux/slab.h>16#include <linux/kfifo.h>17#include <linux/err.h>18#include <linux/module.h>19#include <linux/of.h>20#include <linux/platform_device.h>21#include <linux/pm_runtime.h>22#include <linux/mailbox_controller.h>23#include <linux/mailbox_client.h>24 25#include "mailbox.h"26 27#define MAILBOX_REVISION		0x00028#define MAILBOX_MESSAGE(m)		(0x040 + 4 * (m))29#define MAILBOX_FIFOSTATUS(m)		(0x080 + 4 * (m))30#define MAILBOX_MSGSTATUS(m)		(0x0c0 + 4 * (m))31 32#define OMAP2_MAILBOX_IRQSTATUS(u)	(0x100 + 8 * (u))33#define OMAP2_MAILBOX_IRQENABLE(u)	(0x104 + 8 * (u))34 35#define OMAP4_MAILBOX_IRQSTATUS(u)	(0x104 + 0x10 * (u))36#define OMAP4_MAILBOX_IRQENABLE(u)	(0x108 + 0x10 * (u))37#define OMAP4_MAILBOX_IRQENABLE_CLR(u)	(0x10c + 0x10 * (u))38 39#define MAILBOX_IRQSTATUS(type, u)	(type ? OMAP4_MAILBOX_IRQSTATUS(u) : \40						OMAP2_MAILBOX_IRQSTATUS(u))41#define MAILBOX_IRQENABLE(type, u)	(type ? OMAP4_MAILBOX_IRQENABLE(u) : \42						OMAP2_MAILBOX_IRQENABLE(u))43#define MAILBOX_IRQDISABLE(type, u)	(type ? OMAP4_MAILBOX_IRQENABLE_CLR(u) \44						: OMAP2_MAILBOX_IRQENABLE(u))45 46#define MAILBOX_IRQ_NEWMSG(m)		(1 << (2 * (m)))47#define MAILBOX_IRQ_NOTFULL(m)		(1 << (2 * (m) + 1))48 49/* Interrupt register configuration types */50#define MBOX_INTR_CFG_TYPE1		051#define MBOX_INTR_CFG_TYPE2		152 53typedef enum {54	IRQ_TX = 1,55	IRQ_RX = 2,56} omap_mbox_irq_t;57 58struct omap_mbox_fifo {59	unsigned long msg;60	unsigned long fifo_stat;61	unsigned long msg_stat;62	unsigned long irqenable;63	unsigned long irqstatus;64	unsigned long irqdisable;65	u32 intr_bit;66};67 68struct omap_mbox_match_data {69	u32 intr_type;70};71 72struct omap_mbox_device {73	struct device *dev;74	struct mutex cfg_lock;75	void __iomem *mbox_base;76	u32 *irq_ctx;77	u32 num_users;78	u32 num_fifos;79	u32 intr_type;80};81 82struct omap_mbox {83	const char		*name;84	int			irq;85	struct omap_mbox_device *parent;86	struct omap_mbox_fifo	tx_fifo;87	struct omap_mbox_fifo	rx_fifo;88	u32			intr_type;89	struct mbox_chan	*chan;90	bool			send_no_irq;91};92 93static inline94unsigned int mbox_read_reg(struct omap_mbox_device *mdev, size_t ofs)95{96	return __raw_readl(mdev->mbox_base + ofs);97}98 99static inline100void mbox_write_reg(struct omap_mbox_device *mdev, u32 val, size_t ofs)101{102	__raw_writel(val, mdev->mbox_base + ofs);103}104 105/* Mailbox FIFO handle functions */106static u32 mbox_fifo_read(struct omap_mbox *mbox)107{108	struct omap_mbox_fifo *fifo = &mbox->rx_fifo;109 110	return mbox_read_reg(mbox->parent, fifo->msg);111}112 113static void mbox_fifo_write(struct omap_mbox *mbox, u32 msg)114{115	struct omap_mbox_fifo *fifo = &mbox->tx_fifo;116 117	mbox_write_reg(mbox->parent, msg, fifo->msg);118}119 120static int mbox_fifo_empty(struct omap_mbox *mbox)121{122	struct omap_mbox_fifo *fifo = &mbox->rx_fifo;123 124	return (mbox_read_reg(mbox->parent, fifo->msg_stat) == 0);125}126 127static int mbox_fifo_full(struct omap_mbox *mbox)128{129	struct omap_mbox_fifo *fifo = &mbox->tx_fifo;130 131	return mbox_read_reg(mbox->parent, fifo->fifo_stat);132}133 134/* Mailbox IRQ handle functions */135static void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)136{137	struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ?138				&mbox->tx_fifo : &mbox->rx_fifo;139	u32 bit = fifo->intr_bit;140	u32 irqstatus = fifo->irqstatus;141 142	mbox_write_reg(mbox->parent, bit, irqstatus);143 144	/* Flush posted write for irq status to avoid spurious interrupts */145	mbox_read_reg(mbox->parent, irqstatus);146}147 148static int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)149{150	struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ?151				&mbox->tx_fifo : &mbox->rx_fifo;152	u32 bit = fifo->intr_bit;153	u32 irqenable = fifo->irqenable;154	u32 irqstatus = fifo->irqstatus;155 156	u32 enable = mbox_read_reg(mbox->parent, irqenable);157	u32 status = mbox_read_reg(mbox->parent, irqstatus);158 159	return (int)(enable & status & bit);160}161 162static void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)163{164	u32 l;165	struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ?166				&mbox->tx_fifo : &mbox->rx_fifo;167	u32 bit = fifo->intr_bit;168	u32 irqenable = fifo->irqenable;169 170	l = mbox_read_reg(mbox->parent, irqenable);171	l |= bit;172	mbox_write_reg(mbox->parent, l, irqenable);173}174 175static void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)176{177	struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ?178				&mbox->tx_fifo : &mbox->rx_fifo;179	u32 bit = fifo->intr_bit;180	u32 irqdisable = fifo->irqdisable;181 182	/*183	 * Read and update the interrupt configuration register for pre-OMAP4.184	 * OMAP4 and later SoCs have a dedicated interrupt disabling register.185	 */186	if (!mbox->intr_type)187		bit = mbox_read_reg(mbox->parent, irqdisable) & ~bit;188 189	mbox_write_reg(mbox->parent, bit, irqdisable);190}191 192/*193 * Mailbox interrupt handler194 */195static void __mbox_tx_interrupt(struct omap_mbox *mbox)196{197	omap_mbox_disable_irq(mbox, IRQ_TX);198	ack_mbox_irq(mbox, IRQ_TX);199	mbox_chan_txdone(mbox->chan, 0);200}201 202static void __mbox_rx_interrupt(struct omap_mbox *mbox)203{204	u32 msg;205 206	while (!mbox_fifo_empty(mbox)) {207		msg = mbox_fifo_read(mbox);208		mbox_chan_received_data(mbox->chan, (void *)(uintptr_t)msg);209	}210 211	/* clear IRQ source. */212	ack_mbox_irq(mbox, IRQ_RX);213}214 215static irqreturn_t mbox_interrupt(int irq, void *p)216{217	struct omap_mbox *mbox = p;218 219	if (is_mbox_irq(mbox, IRQ_TX))220		__mbox_tx_interrupt(mbox);221 222	if (is_mbox_irq(mbox, IRQ_RX))223		__mbox_rx_interrupt(mbox);224 225	return IRQ_HANDLED;226}227 228static int omap_mbox_startup(struct omap_mbox *mbox)229{230	int ret = 0;231 232	ret = request_threaded_irq(mbox->irq, NULL, mbox_interrupt,233				   IRQF_SHARED | IRQF_ONESHOT, mbox->name,234				   mbox);235	if (unlikely(ret)) {236		pr_err("failed to register mailbox interrupt:%d\n", ret);237		return ret;238	}239 240	if (mbox->send_no_irq)241		mbox->chan->txdone_method = TXDONE_BY_ACK;242 243	omap_mbox_enable_irq(mbox, IRQ_RX);244 245	return 0;246}247 248static void omap_mbox_fini(struct omap_mbox *mbox)249{250	omap_mbox_disable_irq(mbox, IRQ_RX);251	free_irq(mbox->irq, mbox);252}253 254static int omap_mbox_chan_startup(struct mbox_chan *chan)255{256	struct omap_mbox *mbox = chan->con_priv;257	struct omap_mbox_device *mdev = mbox->parent;258	int ret = 0;259 260	mutex_lock(&mdev->cfg_lock);261	pm_runtime_get_sync(mdev->dev);262	ret = omap_mbox_startup(mbox);263	if (ret)264		pm_runtime_put_sync(mdev->dev);265	mutex_unlock(&mdev->cfg_lock);266	return ret;267}268 269static void omap_mbox_chan_shutdown(struct mbox_chan *chan)270{271	struct omap_mbox *mbox = chan->con_priv;272	struct omap_mbox_device *mdev = mbox->parent;273 274	mutex_lock(&mdev->cfg_lock);275	omap_mbox_fini(mbox);276	pm_runtime_put_sync(mdev->dev);277	mutex_unlock(&mdev->cfg_lock);278}279 280static int omap_mbox_chan_send_noirq(struct omap_mbox *mbox, u32 msg)281{282	if (mbox_fifo_full(mbox))283		return -EBUSY;284 285	omap_mbox_enable_irq(mbox, IRQ_RX);286	mbox_fifo_write(mbox, msg);287	omap_mbox_disable_irq(mbox, IRQ_RX);288 289	/* we must read and ack the interrupt directly from here */290	mbox_fifo_read(mbox);291	ack_mbox_irq(mbox, IRQ_RX);292 293	return 0;294}295 296static int omap_mbox_chan_send(struct omap_mbox *mbox, u32 msg)297{298	if (mbox_fifo_full(mbox)) {299		/* always enable the interrupt */300		omap_mbox_enable_irq(mbox, IRQ_TX);301		return -EBUSY;302	}303 304	mbox_fifo_write(mbox, msg);305 306	/* always enable the interrupt */307	omap_mbox_enable_irq(mbox, IRQ_TX);308	return 0;309}310 311static int omap_mbox_chan_send_data(struct mbox_chan *chan, void *data)312{313	struct omap_mbox *mbox = chan->con_priv;314	int ret;315	u32 msg = (u32)(uintptr_t)(data);316 317	if (!mbox)318		return -EINVAL;319 320	if (mbox->send_no_irq)321		ret = omap_mbox_chan_send_noirq(mbox, msg);322	else323		ret = omap_mbox_chan_send(mbox, msg);324 325	return ret;326}327 328static const struct mbox_chan_ops omap_mbox_chan_ops = {329	.startup        = omap_mbox_chan_startup,330	.send_data      = omap_mbox_chan_send_data,331	.shutdown       = omap_mbox_chan_shutdown,332};333 334#ifdef CONFIG_PM_SLEEP335static int omap_mbox_suspend(struct device *dev)336{337	struct omap_mbox_device *mdev = dev_get_drvdata(dev);338	u32 usr, fifo, reg;339 340	if (pm_runtime_status_suspended(dev))341		return 0;342 343	for (fifo = 0; fifo < mdev->num_fifos; fifo++) {344		if (mbox_read_reg(mdev, MAILBOX_MSGSTATUS(fifo))) {345			dev_err(mdev->dev, "fifo %d has unexpected unread messages\n",346				fifo);347			return -EBUSY;348		}349	}350 351	for (usr = 0; usr < mdev->num_users; usr++) {352		reg = MAILBOX_IRQENABLE(mdev->intr_type, usr);353		mdev->irq_ctx[usr] = mbox_read_reg(mdev, reg);354	}355 356	return 0;357}358 359static int omap_mbox_resume(struct device *dev)360{361	struct omap_mbox_device *mdev = dev_get_drvdata(dev);362	u32 usr, reg;363 364	if (pm_runtime_status_suspended(dev))365		return 0;366 367	for (usr = 0; usr < mdev->num_users; usr++) {368		reg = MAILBOX_IRQENABLE(mdev->intr_type, usr);369		mbox_write_reg(mdev, mdev->irq_ctx[usr], reg);370	}371 372	return 0;373}374#endif375 376static const struct dev_pm_ops omap_mbox_pm_ops = {377	SET_SYSTEM_SLEEP_PM_OPS(omap_mbox_suspend, omap_mbox_resume)378};379 380static const struct omap_mbox_match_data omap2_data = { MBOX_INTR_CFG_TYPE1 };381static const struct omap_mbox_match_data omap4_data = { MBOX_INTR_CFG_TYPE2 };382 383static const struct of_device_id omap_mailbox_of_match[] = {384	{385		.compatible	= "ti,omap2-mailbox",386		.data		= &omap2_data,387	},388	{389		.compatible	= "ti,omap3-mailbox",390		.data		= &omap2_data,391	},392	{393		.compatible	= "ti,omap4-mailbox",394		.data		= &omap4_data,395	},396	{397		.compatible	= "ti,am654-mailbox",398		.data		= &omap4_data,399	},400	{401		.compatible	= "ti,am64-mailbox",402		.data		= &omap4_data,403	},404	{405		/* end */406	},407};408MODULE_DEVICE_TABLE(of, omap_mailbox_of_match);409 410static struct mbox_chan *omap_mbox_of_xlate(struct mbox_controller *controller,411					    const struct of_phandle_args *sp)412{413	phandle phandle = sp->args[0];414	struct device_node *node;415	struct omap_mbox_device *mdev;416	struct omap_mbox *mbox;417	int i;418 419	mdev = dev_get_drvdata(controller->dev);420	if (WARN_ON(!mdev))421		return ERR_PTR(-EINVAL);422 423	node = of_find_node_by_phandle(phandle);424	if (!node) {425		pr_err("%s: could not find node phandle 0x%x\n",426		       __func__, phandle);427		return ERR_PTR(-ENODEV);428	}429 430	for (i = 0; i < controller->num_chans; i++) {431		mbox = controller->chans[i].con_priv;432		if (!strcmp(mbox->name, node->name)) {433			of_node_put(node);434			return &controller->chans[i];435		}436	}437 438	of_node_put(node);439	return ERR_PTR(-ENOENT);440}441 442static int omap_mbox_probe(struct platform_device *pdev)443{444	int ret;445	struct mbox_chan *chnls;446	struct omap_mbox *mbox;447	struct omap_mbox_device *mdev;448	struct omap_mbox_fifo *fifo;449	struct device_node *node = pdev->dev.of_node;450	struct device_node *child;451	const struct omap_mbox_match_data *match_data;452	struct mbox_controller *controller;453	u32 intr_type, info_count;454	u32 num_users, num_fifos;455	u32 tmp[3];456	u32 l;457	int i;458 459	if (!node) {460		pr_err("%s: only DT-based devices are supported\n", __func__);461		return -ENODEV;462	}463 464	match_data = of_device_get_match_data(&pdev->dev);465	if (!match_data)466		return -ENODEV;467	intr_type = match_data->intr_type;468 469	if (of_property_read_u32(node, "ti,mbox-num-users", &num_users))470		return -ENODEV;471 472	if (of_property_read_u32(node, "ti,mbox-num-fifos", &num_fifos))473		return -ENODEV;474 475	info_count = of_get_available_child_count(node);476	if (!info_count) {477		dev_err(&pdev->dev, "no available mbox devices found\n");478		return -ENODEV;479	}480 481	mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL);482	if (!mdev)483		return -ENOMEM;484 485	mdev->mbox_base = devm_platform_ioremap_resource(pdev, 0);486	if (IS_ERR(mdev->mbox_base))487		return PTR_ERR(mdev->mbox_base);488 489	mdev->irq_ctx = devm_kcalloc(&pdev->dev, num_users, sizeof(u32),490				     GFP_KERNEL);491	if (!mdev->irq_ctx)492		return -ENOMEM;493 494	chnls = devm_kcalloc(&pdev->dev, info_count + 1, sizeof(*chnls),495			     GFP_KERNEL);496	if (!chnls)497		return -ENOMEM;498 499	child = NULL;500	for (i = 0; i < info_count; i++) {501		int tx_id, tx_irq, tx_usr;502		int rx_id,         rx_usr;503 504		mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);505		if (!mbox)506			return -ENOMEM;507 508		child = of_get_next_available_child(node, child);509		ret = of_property_read_u32_array(child, "ti,mbox-tx", tmp,510						 ARRAY_SIZE(tmp));511		if (ret)512			return ret;513		tx_id = tmp[0];514		tx_irq = tmp[1];515		tx_usr = tmp[2];516 517		ret = of_property_read_u32_array(child, "ti,mbox-rx", tmp,518						 ARRAY_SIZE(tmp));519		if (ret)520			return ret;521		rx_id = tmp[0];522		/* rx_irq = tmp[1]; */523		rx_usr = tmp[2];524 525		if (tx_id >= num_fifos || rx_id >= num_fifos ||526		    tx_usr >= num_users || rx_usr >= num_users)527			return -EINVAL;528 529		fifo = &mbox->tx_fifo;530		fifo->msg = MAILBOX_MESSAGE(tx_id);531		fifo->fifo_stat = MAILBOX_FIFOSTATUS(tx_id);532		fifo->intr_bit = MAILBOX_IRQ_NOTFULL(tx_id);533		fifo->irqenable = MAILBOX_IRQENABLE(intr_type, tx_usr);534		fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, tx_usr);535		fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, tx_usr);536 537		fifo = &mbox->rx_fifo;538		fifo->msg = MAILBOX_MESSAGE(rx_id);539		fifo->msg_stat =  MAILBOX_MSGSTATUS(rx_id);540		fifo->intr_bit = MAILBOX_IRQ_NEWMSG(rx_id);541		fifo->irqenable = MAILBOX_IRQENABLE(intr_type, rx_usr);542		fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, rx_usr);543		fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, rx_usr);544 545		mbox->send_no_irq = of_property_read_bool(child, "ti,mbox-send-noirq");546		mbox->intr_type = intr_type;547 548		mbox->parent = mdev;549		mbox->name = child->name;550		mbox->irq = platform_get_irq(pdev, tx_irq);551		if (mbox->irq < 0)552			return mbox->irq;553		mbox->chan = &chnls[i];554		chnls[i].con_priv = mbox;555	}556 557	mutex_init(&mdev->cfg_lock);558	mdev->dev = &pdev->dev;559	mdev->num_users = num_users;560	mdev->num_fifos = num_fifos;561	mdev->intr_type = intr_type;562 563	controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL);564	if (!controller)565		return -ENOMEM;566	/*567	 * OMAP/K3 Mailbox IP does not have a Tx-Done IRQ, but rather a Tx-Ready568	 * IRQ and is needed to run the Tx state machine569	 */570	controller->txdone_irq = true;571	controller->dev = mdev->dev;572	controller->ops = &omap_mbox_chan_ops;573	controller->chans = chnls;574	controller->num_chans = info_count;575	controller->of_xlate = omap_mbox_of_xlate;576	ret = devm_mbox_controller_register(mdev->dev, controller);577	if (ret)578		return ret;579 580	platform_set_drvdata(pdev, mdev);581	devm_pm_runtime_enable(mdev->dev);582 583	ret = pm_runtime_resume_and_get(mdev->dev);584	if (ret < 0)585		return ret;586 587	/*588	 * just print the raw revision register, the format is not589	 * uniform across all SoCs590	 */591	l = mbox_read_reg(mdev, MAILBOX_REVISION);592	dev_info(mdev->dev, "omap mailbox rev 0x%x\n", l);593 594	ret = pm_runtime_put_sync(mdev->dev);595	if (ret < 0 && ret != -ENOSYS)596		return ret;597 598	return 0;599}600 601static struct platform_driver omap_mbox_driver = {602	.probe	= omap_mbox_probe,603	.driver	= {604		.name = "omap-mailbox",605		.pm = &omap_mbox_pm_ops,606		.of_match_table = omap_mailbox_of_match,607	},608};609module_platform_driver(omap_mbox_driver);610 611MODULE_LICENSE("GPL v2");612MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging");613MODULE_AUTHOR("Toshihiro Kobayashi");614MODULE_AUTHOR("Hiroshi DOYU");615