18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Texas Instruments' Message Manager Driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/
68c2ecf20Sopenharmony_ci *	Nishanth Menon
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, __func__
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/device.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/io.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/mailbox_controller.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/of_device.h>
188c2ecf20Sopenharmony_ci#include <linux/of.h>
198c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
208c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
218c2ecf20Sopenharmony_ci#include <linux/soc/ti/ti-msgmgr.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define Q_DATA_OFFSET(proxy, queue, reg)	\
248c2ecf20Sopenharmony_ci		     ((0x10000 * (proxy)) + (0x80 * (queue)) + ((reg) * 4))
258c2ecf20Sopenharmony_ci#define Q_STATE_OFFSET(queue)			((queue) * 0x4)
268c2ecf20Sopenharmony_ci#define Q_STATE_ENTRY_COUNT_MASK		(0xFFF000)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define SPROXY_THREAD_OFFSET(tid) (0x1000 * (tid))
298c2ecf20Sopenharmony_ci#define SPROXY_THREAD_DATA_OFFSET(tid, reg) \
308c2ecf20Sopenharmony_ci	(SPROXY_THREAD_OFFSET(tid) + ((reg) * 0x4) + 0x4)
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define SPROXY_THREAD_STATUS_OFFSET(tid) (SPROXY_THREAD_OFFSET(tid))
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define SPROXY_THREAD_STATUS_COUNT_MASK (0xFF)
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define SPROXY_THREAD_CTRL_OFFSET(tid) (0x1000 + SPROXY_THREAD_OFFSET(tid))
378c2ecf20Sopenharmony_ci#define SPROXY_THREAD_CTRL_DIR_MASK (0x1 << 31)
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/**
408c2ecf20Sopenharmony_ci * struct ti_msgmgr_valid_queue_desc - SoC valid queues meant for this processor
418c2ecf20Sopenharmony_ci * @queue_id:	Queue Number for this path
428c2ecf20Sopenharmony_ci * @proxy_id:	Proxy ID representing the processor in SoC
438c2ecf20Sopenharmony_ci * @is_tx:	Is this a receive path?
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_cistruct ti_msgmgr_valid_queue_desc {
468c2ecf20Sopenharmony_ci	u8 queue_id;
478c2ecf20Sopenharmony_ci	u8 proxy_id;
488c2ecf20Sopenharmony_ci	bool is_tx;
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/**
528c2ecf20Sopenharmony_ci * struct ti_msgmgr_desc - Description of message manager integration
538c2ecf20Sopenharmony_ci * @queue_count:	Number of Queues
548c2ecf20Sopenharmony_ci * @max_message_size:	Message size in bytes
558c2ecf20Sopenharmony_ci * @max_messages:	Number of messages
568c2ecf20Sopenharmony_ci * @data_first_reg:	First data register for proxy data region
578c2ecf20Sopenharmony_ci * @data_last_reg:	Last data register for proxy data region
588c2ecf20Sopenharmony_ci * @status_cnt_mask:	Mask for getting the status value
598c2ecf20Sopenharmony_ci * @status_err_mask:	Mask for getting the error value, if applicable
608c2ecf20Sopenharmony_ci * @tx_polled:		Do I need to use polled mechanism for tx
618c2ecf20Sopenharmony_ci * @tx_poll_timeout_ms: Timeout in ms if polled
628c2ecf20Sopenharmony_ci * @valid_queues:	List of Valid queues that the processor can access
638c2ecf20Sopenharmony_ci * @data_region_name:	Name of the proxy data region
648c2ecf20Sopenharmony_ci * @status_region_name:	Name of the proxy status region
658c2ecf20Sopenharmony_ci * @ctrl_region_name:	Name of the proxy control region
668c2ecf20Sopenharmony_ci * @num_valid_queues:	Number of valid queues
678c2ecf20Sopenharmony_ci * @is_sproxy:		Is this an Secure Proxy instance?
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci * This structure is used in of match data to describe how integration
708c2ecf20Sopenharmony_ci * for a specific compatible SoC is done.
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_cistruct ti_msgmgr_desc {
738c2ecf20Sopenharmony_ci	u8 queue_count;
748c2ecf20Sopenharmony_ci	u8 max_message_size;
758c2ecf20Sopenharmony_ci	u8 max_messages;
768c2ecf20Sopenharmony_ci	u8 data_first_reg;
778c2ecf20Sopenharmony_ci	u8 data_last_reg;
788c2ecf20Sopenharmony_ci	u32 status_cnt_mask;
798c2ecf20Sopenharmony_ci	u32 status_err_mask;
808c2ecf20Sopenharmony_ci	bool tx_polled;
818c2ecf20Sopenharmony_ci	int tx_poll_timeout_ms;
828c2ecf20Sopenharmony_ci	const struct ti_msgmgr_valid_queue_desc *valid_queues;
838c2ecf20Sopenharmony_ci	const char *data_region_name;
848c2ecf20Sopenharmony_ci	const char *status_region_name;
858c2ecf20Sopenharmony_ci	const char *ctrl_region_name;
868c2ecf20Sopenharmony_ci	int num_valid_queues;
878c2ecf20Sopenharmony_ci	bool is_sproxy;
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/**
918c2ecf20Sopenharmony_ci * struct ti_queue_inst - Description of a queue instance
928c2ecf20Sopenharmony_ci * @name:	Queue Name
938c2ecf20Sopenharmony_ci * @queue_id:	Queue Identifier as mapped on SoC
948c2ecf20Sopenharmony_ci * @proxy_id:	Proxy Identifier as mapped on SoC
958c2ecf20Sopenharmony_ci * @irq:	IRQ for Rx Queue
968c2ecf20Sopenharmony_ci * @is_tx:	'true' if transmit queue, else, 'false'
978c2ecf20Sopenharmony_ci * @queue_buff_start: First register of Data Buffer
988c2ecf20Sopenharmony_ci * @queue_buff_end: Last (or confirmation) register of Data buffer
998c2ecf20Sopenharmony_ci * @queue_state: Queue status register
1008c2ecf20Sopenharmony_ci * @queue_ctrl: Queue Control register
1018c2ecf20Sopenharmony_ci * @chan:	Mailbox channel
1028c2ecf20Sopenharmony_ci * @rx_buff:	Receive buffer pointer allocated at probe, max_message_size
1038c2ecf20Sopenharmony_ci */
1048c2ecf20Sopenharmony_cistruct ti_queue_inst {
1058c2ecf20Sopenharmony_ci	char name[30];
1068c2ecf20Sopenharmony_ci	u8 queue_id;
1078c2ecf20Sopenharmony_ci	u8 proxy_id;
1088c2ecf20Sopenharmony_ci	int irq;
1098c2ecf20Sopenharmony_ci	bool is_tx;
1108c2ecf20Sopenharmony_ci	void __iomem *queue_buff_start;
1118c2ecf20Sopenharmony_ci	void __iomem *queue_buff_end;
1128c2ecf20Sopenharmony_ci	void __iomem *queue_state;
1138c2ecf20Sopenharmony_ci	void __iomem *queue_ctrl;
1148c2ecf20Sopenharmony_ci	struct mbox_chan *chan;
1158c2ecf20Sopenharmony_ci	u32 *rx_buff;
1168c2ecf20Sopenharmony_ci};
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/**
1198c2ecf20Sopenharmony_ci * struct ti_msgmgr_inst - Description of a Message Manager Instance
1208c2ecf20Sopenharmony_ci * @dev:	device pointer corresponding to the Message Manager instance
1218c2ecf20Sopenharmony_ci * @desc:	Description of the SoC integration
1228c2ecf20Sopenharmony_ci * @queue_proxy_region:	Queue proxy region where queue buffers are located
1238c2ecf20Sopenharmony_ci * @queue_state_debug_region:	Queue status register regions
1248c2ecf20Sopenharmony_ci * @queue_ctrl_region:	Queue Control register regions
1258c2ecf20Sopenharmony_ci * @num_valid_queues:	Number of valid queues defined for the processor
1268c2ecf20Sopenharmony_ci *		Note: other queues are probably reserved for other processors
1278c2ecf20Sopenharmony_ci *		in the SoC.
1288c2ecf20Sopenharmony_ci * @qinsts:	Array of valid Queue Instances for the Processor
1298c2ecf20Sopenharmony_ci * @mbox:	Mailbox Controller
1308c2ecf20Sopenharmony_ci * @chans:	Array for channels corresponding to the Queue Instances.
1318c2ecf20Sopenharmony_ci */
1328c2ecf20Sopenharmony_cistruct ti_msgmgr_inst {
1338c2ecf20Sopenharmony_ci	struct device *dev;
1348c2ecf20Sopenharmony_ci	const struct ti_msgmgr_desc *desc;
1358c2ecf20Sopenharmony_ci	void __iomem *queue_proxy_region;
1368c2ecf20Sopenharmony_ci	void __iomem *queue_state_debug_region;
1378c2ecf20Sopenharmony_ci	void __iomem *queue_ctrl_region;
1388c2ecf20Sopenharmony_ci	u8 num_valid_queues;
1398c2ecf20Sopenharmony_ci	struct ti_queue_inst *qinsts;
1408c2ecf20Sopenharmony_ci	struct mbox_controller mbox;
1418c2ecf20Sopenharmony_ci	struct mbox_chan *chans;
1428c2ecf20Sopenharmony_ci};
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/**
1458c2ecf20Sopenharmony_ci * ti_msgmgr_queue_get_num_messages() - Get the number of pending messages
1468c2ecf20Sopenharmony_ci * @d:		Description of message manager
1478c2ecf20Sopenharmony_ci * @qinst:	Queue instance for which we check the number of pending messages
1488c2ecf20Sopenharmony_ci *
1498c2ecf20Sopenharmony_ci * Return: number of messages pending in the queue (0 == no pending messages)
1508c2ecf20Sopenharmony_ci */
1518c2ecf20Sopenharmony_cistatic inline int
1528c2ecf20Sopenharmony_citi_msgmgr_queue_get_num_messages(const struct ti_msgmgr_desc *d,
1538c2ecf20Sopenharmony_ci				 struct ti_queue_inst *qinst)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	u32 val;
1568c2ecf20Sopenharmony_ci	u32 status_cnt_mask = d->status_cnt_mask;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/*
1598c2ecf20Sopenharmony_ci	 * We cannot use relaxed operation here - update may happen
1608c2ecf20Sopenharmony_ci	 * real-time.
1618c2ecf20Sopenharmony_ci	 */
1628c2ecf20Sopenharmony_ci	val = readl(qinst->queue_state) & status_cnt_mask;
1638c2ecf20Sopenharmony_ci	val >>= __ffs(status_cnt_mask);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	return val;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci/**
1698c2ecf20Sopenharmony_ci * ti_msgmgr_queue_is_error() - Check to see if there is queue error
1708c2ecf20Sopenharmony_ci * @d:		Description of message manager
1718c2ecf20Sopenharmony_ci * @qinst:	Queue instance for which we check the number of pending messages
1728c2ecf20Sopenharmony_ci *
1738c2ecf20Sopenharmony_ci * Return: true if error, else false
1748c2ecf20Sopenharmony_ci */
1758c2ecf20Sopenharmony_cistatic inline bool ti_msgmgr_queue_is_error(const struct ti_msgmgr_desc *d,
1768c2ecf20Sopenharmony_ci					    struct ti_queue_inst *qinst)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	u32 val;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* Msgmgr has no error detection */
1818c2ecf20Sopenharmony_ci	if (!d->is_sproxy)
1828c2ecf20Sopenharmony_ci		return false;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/*
1858c2ecf20Sopenharmony_ci	 * We cannot use relaxed operation here - update may happen
1868c2ecf20Sopenharmony_ci	 * real-time.
1878c2ecf20Sopenharmony_ci	 */
1888c2ecf20Sopenharmony_ci	val = readl(qinst->queue_state) & d->status_err_mask;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	return val ? true : false;
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci/**
1948c2ecf20Sopenharmony_ci * ti_msgmgr_queue_rx_interrupt() - Interrupt handler for receive Queue
1958c2ecf20Sopenharmony_ci * @irq:	Interrupt number
1968c2ecf20Sopenharmony_ci * @p:		Channel Pointer
1978c2ecf20Sopenharmony_ci *
1988c2ecf20Sopenharmony_ci * Return: -EINVAL if there is no instance
1998c2ecf20Sopenharmony_ci * IRQ_NONE if the interrupt is not ours.
2008c2ecf20Sopenharmony_ci * IRQ_HANDLED if the rx interrupt was successfully handled.
2018c2ecf20Sopenharmony_ci */
2028c2ecf20Sopenharmony_cistatic irqreturn_t ti_msgmgr_queue_rx_interrupt(int irq, void *p)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	struct mbox_chan *chan = p;
2058c2ecf20Sopenharmony_ci	struct device *dev = chan->mbox->dev;
2068c2ecf20Sopenharmony_ci	struct ti_msgmgr_inst *inst = dev_get_drvdata(dev);
2078c2ecf20Sopenharmony_ci	struct ti_queue_inst *qinst = chan->con_priv;
2088c2ecf20Sopenharmony_ci	const struct ti_msgmgr_desc *desc;
2098c2ecf20Sopenharmony_ci	int msg_count, num_words;
2108c2ecf20Sopenharmony_ci	struct ti_msgmgr_message message;
2118c2ecf20Sopenharmony_ci	void __iomem *data_reg;
2128c2ecf20Sopenharmony_ci	u32 *word_data;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if (WARN_ON(!inst)) {
2158c2ecf20Sopenharmony_ci		dev_err(dev, "no platform drv data??\n");
2168c2ecf20Sopenharmony_ci		return -EINVAL;
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	/* Do I have an invalid interrupt source? */
2208c2ecf20Sopenharmony_ci	if (qinst->is_tx) {
2218c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot handle rx interrupt on tx channel %s\n",
2228c2ecf20Sopenharmony_ci			qinst->name);
2238c2ecf20Sopenharmony_ci		return IRQ_NONE;
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	desc = inst->desc;
2278c2ecf20Sopenharmony_ci	if (ti_msgmgr_queue_is_error(desc, qinst)) {
2288c2ecf20Sopenharmony_ci		dev_err(dev, "Error on Rx channel %s\n", qinst->name);
2298c2ecf20Sopenharmony_ci		return IRQ_NONE;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	/* Do I actually have messages to read? */
2338c2ecf20Sopenharmony_ci	msg_count = ti_msgmgr_queue_get_num_messages(desc, qinst);
2348c2ecf20Sopenharmony_ci	if (!msg_count) {
2358c2ecf20Sopenharmony_ci		/* Shared IRQ? */
2368c2ecf20Sopenharmony_ci		dev_dbg(dev, "Spurious event - 0 pending data!\n");
2378c2ecf20Sopenharmony_ci		return IRQ_NONE;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/*
2418c2ecf20Sopenharmony_ci	 * I have no idea about the protocol being used to communicate with the
2428c2ecf20Sopenharmony_ci	 * remote producer - 0 could be valid data, so I wont make a judgement
2438c2ecf20Sopenharmony_ci	 * of how many bytes I should be reading. Let the client figure this
2448c2ecf20Sopenharmony_ci	 * out.. I just read the full message and pass it on..
2458c2ecf20Sopenharmony_ci	 */
2468c2ecf20Sopenharmony_ci	message.len = desc->max_message_size;
2478c2ecf20Sopenharmony_ci	message.buf = (u8 *)qinst->rx_buff;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	/*
2508c2ecf20Sopenharmony_ci	 * NOTE about register access involved here:
2518c2ecf20Sopenharmony_ci	 * the hardware block is implemented with 32bit access operations and no
2528c2ecf20Sopenharmony_ci	 * support for data splitting.  We don't want the hardware to misbehave
2538c2ecf20Sopenharmony_ci	 * with sub 32bit access - For example: if the last register read is
2548c2ecf20Sopenharmony_ci	 * split into byte wise access, it can result in the queue getting
2558c2ecf20Sopenharmony_ci	 * stuck or indeterminate behavior. An out of order read operation may
2568c2ecf20Sopenharmony_ci	 * result in weird data results as well.
2578c2ecf20Sopenharmony_ci	 * Hence, we do not use memcpy_fromio or __ioread32_copy here, instead
2588c2ecf20Sopenharmony_ci	 * we depend on readl for the purpose.
2598c2ecf20Sopenharmony_ci	 *
2608c2ecf20Sopenharmony_ci	 * Also note that the final register read automatically marks the
2618c2ecf20Sopenharmony_ci	 * queue message as read.
2628c2ecf20Sopenharmony_ci	 */
2638c2ecf20Sopenharmony_ci	for (data_reg = qinst->queue_buff_start, word_data = qinst->rx_buff,
2648c2ecf20Sopenharmony_ci	     num_words = (desc->max_message_size / sizeof(u32));
2658c2ecf20Sopenharmony_ci	     num_words; num_words--, data_reg += sizeof(u32), word_data++)
2668c2ecf20Sopenharmony_ci		*word_data = readl(data_reg);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/*
2698c2ecf20Sopenharmony_ci	 * Last register read automatically clears the IRQ if only 1 message
2708c2ecf20Sopenharmony_ci	 * is pending - so send the data up the stack..
2718c2ecf20Sopenharmony_ci	 * NOTE: Client is expected to be as optimal as possible, since
2728c2ecf20Sopenharmony_ci	 * we invoke the handler in IRQ context.
2738c2ecf20Sopenharmony_ci	 */
2748c2ecf20Sopenharmony_ci	mbox_chan_received_data(chan, (void *)&message);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci/**
2808c2ecf20Sopenharmony_ci * ti_msgmgr_queue_peek_data() - Peek to see if there are any rx messages.
2818c2ecf20Sopenharmony_ci * @chan:	Channel Pointer
2828c2ecf20Sopenharmony_ci *
2838c2ecf20Sopenharmony_ci * Return: 'true' if there is pending rx data, 'false' if there is none.
2848c2ecf20Sopenharmony_ci */
2858c2ecf20Sopenharmony_cistatic bool ti_msgmgr_queue_peek_data(struct mbox_chan *chan)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	struct ti_queue_inst *qinst = chan->con_priv;
2888c2ecf20Sopenharmony_ci	struct device *dev = chan->mbox->dev;
2898c2ecf20Sopenharmony_ci	struct ti_msgmgr_inst *inst = dev_get_drvdata(dev);
2908c2ecf20Sopenharmony_ci	const struct ti_msgmgr_desc *desc = inst->desc;
2918c2ecf20Sopenharmony_ci	int msg_count;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (qinst->is_tx)
2948c2ecf20Sopenharmony_ci		return false;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (ti_msgmgr_queue_is_error(desc, qinst)) {
2978c2ecf20Sopenharmony_ci		dev_err(dev, "Error on channel %s\n", qinst->name);
2988c2ecf20Sopenharmony_ci		return false;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	msg_count = ti_msgmgr_queue_get_num_messages(desc, qinst);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return msg_count ? true : false;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci/**
3078c2ecf20Sopenharmony_ci * ti_msgmgr_last_tx_done() - See if all the tx messages are sent
3088c2ecf20Sopenharmony_ci * @chan:	Channel pointer
3098c2ecf20Sopenharmony_ci *
3108c2ecf20Sopenharmony_ci * Return: 'true' is no pending tx data, 'false' if there are any.
3118c2ecf20Sopenharmony_ci */
3128c2ecf20Sopenharmony_cistatic bool ti_msgmgr_last_tx_done(struct mbox_chan *chan)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	struct ti_queue_inst *qinst = chan->con_priv;
3158c2ecf20Sopenharmony_ci	struct device *dev = chan->mbox->dev;
3168c2ecf20Sopenharmony_ci	struct ti_msgmgr_inst *inst = dev_get_drvdata(dev);
3178c2ecf20Sopenharmony_ci	const struct ti_msgmgr_desc *desc = inst->desc;
3188c2ecf20Sopenharmony_ci	int msg_count;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (!qinst->is_tx)
3218c2ecf20Sopenharmony_ci		return false;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (ti_msgmgr_queue_is_error(desc, qinst)) {
3248c2ecf20Sopenharmony_ci		dev_err(dev, "Error on channel %s\n", qinst->name);
3258c2ecf20Sopenharmony_ci		return false;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	msg_count = ti_msgmgr_queue_get_num_messages(desc, qinst);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (desc->is_sproxy) {
3318c2ecf20Sopenharmony_ci		/* In secure proxy, msg_count indicates how many we can send */
3328c2ecf20Sopenharmony_ci		return msg_count ? true : false;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/* if we have any messages pending.. */
3368c2ecf20Sopenharmony_ci	return msg_count ? false : true;
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci/**
3408c2ecf20Sopenharmony_ci * ti_msgmgr_send_data() - Send data
3418c2ecf20Sopenharmony_ci * @chan:	Channel Pointer
3428c2ecf20Sopenharmony_ci * @data:	ti_msgmgr_message * Message Pointer
3438c2ecf20Sopenharmony_ci *
3448c2ecf20Sopenharmony_ci * Return: 0 if all goes good, else appropriate error messages.
3458c2ecf20Sopenharmony_ci */
3468c2ecf20Sopenharmony_cistatic int ti_msgmgr_send_data(struct mbox_chan *chan, void *data)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct device *dev = chan->mbox->dev;
3498c2ecf20Sopenharmony_ci	struct ti_msgmgr_inst *inst = dev_get_drvdata(dev);
3508c2ecf20Sopenharmony_ci	const struct ti_msgmgr_desc *desc;
3518c2ecf20Sopenharmony_ci	struct ti_queue_inst *qinst = chan->con_priv;
3528c2ecf20Sopenharmony_ci	int num_words, trail_bytes;
3538c2ecf20Sopenharmony_ci	struct ti_msgmgr_message *message = data;
3548c2ecf20Sopenharmony_ci	void __iomem *data_reg;
3558c2ecf20Sopenharmony_ci	u32 *word_data;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	if (WARN_ON(!inst)) {
3588c2ecf20Sopenharmony_ci		dev_err(dev, "no platform drv data??\n");
3598c2ecf20Sopenharmony_ci		return -EINVAL;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci	desc = inst->desc;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	if (ti_msgmgr_queue_is_error(desc, qinst)) {
3648c2ecf20Sopenharmony_ci		dev_err(dev, "Error on channel %s\n", qinst->name);
3658c2ecf20Sopenharmony_ci		return false;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	if (desc->max_message_size < message->len) {
3698c2ecf20Sopenharmony_ci		dev_err(dev, "Queue %s message length %zu > max %d\n",
3708c2ecf20Sopenharmony_ci			qinst->name, message->len, desc->max_message_size);
3718c2ecf20Sopenharmony_ci		return -EINVAL;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	/* NOTE: Constraints similar to rx path exists here as well */
3758c2ecf20Sopenharmony_ci	for (data_reg = qinst->queue_buff_start,
3768c2ecf20Sopenharmony_ci	     num_words = message->len / sizeof(u32),
3778c2ecf20Sopenharmony_ci	     word_data = (u32 *)message->buf;
3788c2ecf20Sopenharmony_ci	     num_words; num_words--, data_reg += sizeof(u32), word_data++)
3798c2ecf20Sopenharmony_ci		writel(*word_data, data_reg);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	trail_bytes = message->len % sizeof(u32);
3828c2ecf20Sopenharmony_ci	if (trail_bytes) {
3838c2ecf20Sopenharmony_ci		u32 data_trail = *word_data;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci		/* Ensure all unused data is 0 */
3868c2ecf20Sopenharmony_ci		data_trail &= 0xFFFFFFFF >> (8 * (sizeof(u32) - trail_bytes));
3878c2ecf20Sopenharmony_ci		writel(data_trail, data_reg);
3888c2ecf20Sopenharmony_ci		data_reg += sizeof(u32);
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/*
3928c2ecf20Sopenharmony_ci	 * 'data_reg' indicates next register to write. If we did not already
3938c2ecf20Sopenharmony_ci	 * write on tx complete reg(last reg), we must do so for transmit
3948c2ecf20Sopenharmony_ci	 * In addition, we also need to make sure all intermediate data
3958c2ecf20Sopenharmony_ci	 * registers(if any required), are reset to 0 for TISCI backward
3968c2ecf20Sopenharmony_ci	 * compatibility to be maintained.
3978c2ecf20Sopenharmony_ci	 */
3988c2ecf20Sopenharmony_ci	while (data_reg <= qinst->queue_buff_end) {
3998c2ecf20Sopenharmony_ci		writel(0, data_reg);
4008c2ecf20Sopenharmony_ci		data_reg += sizeof(u32);
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	return 0;
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci/**
4078c2ecf20Sopenharmony_ci *  ti_msgmgr_queue_rx_irq_req() - RX IRQ request
4088c2ecf20Sopenharmony_ci *  @dev:	device pointer
4098c2ecf20Sopenharmony_ci *  @d:		descriptor for ti_msgmgr
4108c2ecf20Sopenharmony_ci *  @qinst:	Queue instance
4118c2ecf20Sopenharmony_ci *  @chan:	Channel pointer
4128c2ecf20Sopenharmony_ci */
4138c2ecf20Sopenharmony_cistatic int ti_msgmgr_queue_rx_irq_req(struct device *dev,
4148c2ecf20Sopenharmony_ci				      const struct ti_msgmgr_desc *d,
4158c2ecf20Sopenharmony_ci				      struct ti_queue_inst *qinst,
4168c2ecf20Sopenharmony_ci				      struct mbox_chan *chan)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	int ret = 0;
4198c2ecf20Sopenharmony_ci	char of_rx_irq_name[7];
4208c2ecf20Sopenharmony_ci	struct device_node *np;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	snprintf(of_rx_irq_name, sizeof(of_rx_irq_name),
4238c2ecf20Sopenharmony_ci		 "rx_%03d", d->is_sproxy ? qinst->proxy_id : qinst->queue_id);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	/* Get the IRQ if not found */
4268c2ecf20Sopenharmony_ci	if (qinst->irq < 0) {
4278c2ecf20Sopenharmony_ci		np = of_node_get(dev->of_node);
4288c2ecf20Sopenharmony_ci		if (!np)
4298c2ecf20Sopenharmony_ci			return -ENODATA;
4308c2ecf20Sopenharmony_ci		qinst->irq = of_irq_get_byname(np, of_rx_irq_name);
4318c2ecf20Sopenharmony_ci		of_node_put(np);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci		if (qinst->irq < 0) {
4348c2ecf20Sopenharmony_ci			dev_err(dev,
4358c2ecf20Sopenharmony_ci				"QID %d PID %d:No IRQ[%s]: %d\n",
4368c2ecf20Sopenharmony_ci				qinst->queue_id, qinst->proxy_id,
4378c2ecf20Sopenharmony_ci				of_rx_irq_name, qinst->irq);
4388c2ecf20Sopenharmony_ci			return qinst->irq;
4398c2ecf20Sopenharmony_ci		}
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	/* With the expectation that the IRQ might be shared in SoC */
4438c2ecf20Sopenharmony_ci	ret = request_irq(qinst->irq, ti_msgmgr_queue_rx_interrupt,
4448c2ecf20Sopenharmony_ci			  IRQF_SHARED, qinst->name, chan);
4458c2ecf20Sopenharmony_ci	if (ret) {
4468c2ecf20Sopenharmony_ci		dev_err(dev, "Unable to get IRQ %d on %s(res=%d)\n",
4478c2ecf20Sopenharmony_ci			qinst->irq, qinst->name, ret);
4488c2ecf20Sopenharmony_ci	}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	return ret;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci/**
4548c2ecf20Sopenharmony_ci * ti_msgmgr_queue_startup() - Startup queue
4558c2ecf20Sopenharmony_ci * @chan:	Channel pointer
4568c2ecf20Sopenharmony_ci *
4578c2ecf20Sopenharmony_ci * Return: 0 if all goes good, else return corresponding error message
4588c2ecf20Sopenharmony_ci */
4598c2ecf20Sopenharmony_cistatic int ti_msgmgr_queue_startup(struct mbox_chan *chan)
4608c2ecf20Sopenharmony_ci{
4618c2ecf20Sopenharmony_ci	struct device *dev = chan->mbox->dev;
4628c2ecf20Sopenharmony_ci	struct ti_msgmgr_inst *inst = dev_get_drvdata(dev);
4638c2ecf20Sopenharmony_ci	struct ti_queue_inst *qinst = chan->con_priv;
4648c2ecf20Sopenharmony_ci	const struct ti_msgmgr_desc *d = inst->desc;
4658c2ecf20Sopenharmony_ci	int ret;
4668c2ecf20Sopenharmony_ci	int msg_count;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	/*
4698c2ecf20Sopenharmony_ci	 * If sproxy is starting and can send messages, we are a Tx thread,
4708c2ecf20Sopenharmony_ci	 * else Rx
4718c2ecf20Sopenharmony_ci	 */
4728c2ecf20Sopenharmony_ci	if (d->is_sproxy) {
4738c2ecf20Sopenharmony_ci		qinst->is_tx = (readl(qinst->queue_ctrl) &
4748c2ecf20Sopenharmony_ci				SPROXY_THREAD_CTRL_DIR_MASK) ? false : true;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci		msg_count = ti_msgmgr_queue_get_num_messages(d, qinst);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		if (!msg_count && qinst->is_tx) {
4798c2ecf20Sopenharmony_ci			dev_err(dev, "%s: Cannot transmit with 0 credits!\n",
4808c2ecf20Sopenharmony_ci				qinst->name);
4818c2ecf20Sopenharmony_ci			return -EINVAL;
4828c2ecf20Sopenharmony_ci		}
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	if (!qinst->is_tx) {
4868c2ecf20Sopenharmony_ci		/* Allocate usage buffer for rx */
4878c2ecf20Sopenharmony_ci		qinst->rx_buff = kzalloc(d->max_message_size, GFP_KERNEL);
4888c2ecf20Sopenharmony_ci		if (!qinst->rx_buff)
4898c2ecf20Sopenharmony_ci			return -ENOMEM;
4908c2ecf20Sopenharmony_ci		/* Request IRQ */
4918c2ecf20Sopenharmony_ci		ret = ti_msgmgr_queue_rx_irq_req(dev, d, qinst, chan);
4928c2ecf20Sopenharmony_ci		if (ret) {
4938c2ecf20Sopenharmony_ci			kfree(qinst->rx_buff);
4948c2ecf20Sopenharmony_ci			return ret;
4958c2ecf20Sopenharmony_ci		}
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	return 0;
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci/**
5028c2ecf20Sopenharmony_ci * ti_msgmgr_queue_shutdown() - Shutdown the queue
5038c2ecf20Sopenharmony_ci * @chan:	Channel pointer
5048c2ecf20Sopenharmony_ci */
5058c2ecf20Sopenharmony_cistatic void ti_msgmgr_queue_shutdown(struct mbox_chan *chan)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	struct ti_queue_inst *qinst = chan->con_priv;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	if (!qinst->is_tx) {
5108c2ecf20Sopenharmony_ci		free_irq(qinst->irq, chan);
5118c2ecf20Sopenharmony_ci		kfree(qinst->rx_buff);
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci/**
5168c2ecf20Sopenharmony_ci * ti_msgmgr_of_xlate() - Translation of phandle to queue
5178c2ecf20Sopenharmony_ci * @mbox:	Mailbox controller
5188c2ecf20Sopenharmony_ci * @p:		phandle pointer
5198c2ecf20Sopenharmony_ci *
5208c2ecf20Sopenharmony_ci * Return: Mailbox channel corresponding to the queue, else return error
5218c2ecf20Sopenharmony_ci * pointer.
5228c2ecf20Sopenharmony_ci */
5238c2ecf20Sopenharmony_cistatic struct mbox_chan *ti_msgmgr_of_xlate(struct mbox_controller *mbox,
5248c2ecf20Sopenharmony_ci					    const struct of_phandle_args *p)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	struct ti_msgmgr_inst *inst;
5278c2ecf20Sopenharmony_ci	int req_qid, req_pid;
5288c2ecf20Sopenharmony_ci	struct ti_queue_inst *qinst;
5298c2ecf20Sopenharmony_ci	const struct ti_msgmgr_desc *d;
5308c2ecf20Sopenharmony_ci	int i, ncells;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	inst = container_of(mbox, struct ti_msgmgr_inst, mbox);
5338c2ecf20Sopenharmony_ci	if (WARN_ON(!inst))
5348c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	d = inst->desc;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (d->is_sproxy)
5398c2ecf20Sopenharmony_ci		ncells = 1;
5408c2ecf20Sopenharmony_ci	else
5418c2ecf20Sopenharmony_ci		ncells = 2;
5428c2ecf20Sopenharmony_ci	if (p->args_count != ncells) {
5438c2ecf20Sopenharmony_ci		dev_err(inst->dev, "Invalid arguments in dt[%d]. Must be %d\n",
5448c2ecf20Sopenharmony_ci			p->args_count, ncells);
5458c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci	if (ncells == 1) {
5488c2ecf20Sopenharmony_ci		req_qid = 0;
5498c2ecf20Sopenharmony_ci		req_pid = p->args[0];
5508c2ecf20Sopenharmony_ci	} else {
5518c2ecf20Sopenharmony_ci		req_qid = p->args[0];
5528c2ecf20Sopenharmony_ci		req_pid = p->args[1];
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	if (d->is_sproxy) {
5568c2ecf20Sopenharmony_ci		if (req_pid >= d->num_valid_queues)
5578c2ecf20Sopenharmony_ci			goto err;
5588c2ecf20Sopenharmony_ci		qinst = &inst->qinsts[req_pid];
5598c2ecf20Sopenharmony_ci		return qinst->chan;
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	for (qinst = inst->qinsts, i = 0; i < inst->num_valid_queues;
5638c2ecf20Sopenharmony_ci	     i++, qinst++) {
5648c2ecf20Sopenharmony_ci		if (req_qid == qinst->queue_id && req_pid == qinst->proxy_id)
5658c2ecf20Sopenharmony_ci			return qinst->chan;
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cierr:
5698c2ecf20Sopenharmony_ci	dev_err(inst->dev, "Queue ID %d, Proxy ID %d is wrong on %pOFn\n",
5708c2ecf20Sopenharmony_ci		req_qid, req_pid, p->np);
5718c2ecf20Sopenharmony_ci	return ERR_PTR(-ENOENT);
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci/**
5758c2ecf20Sopenharmony_ci * ti_msgmgr_queue_setup() - Setup data structures for each queue instance
5768c2ecf20Sopenharmony_ci * @idx:	index of the queue
5778c2ecf20Sopenharmony_ci * @dev:	pointer to the message manager device
5788c2ecf20Sopenharmony_ci * @np:		pointer to the of node
5798c2ecf20Sopenharmony_ci * @inst:	Queue instance pointer
5808c2ecf20Sopenharmony_ci * @d:		Message Manager instance description data
5818c2ecf20Sopenharmony_ci * @qd:		Queue description data
5828c2ecf20Sopenharmony_ci * @qinst:	Queue instance pointer
5838c2ecf20Sopenharmony_ci * @chan:	pointer to mailbox channel
5848c2ecf20Sopenharmony_ci *
5858c2ecf20Sopenharmony_ci * Return: 0 if all went well, else return corresponding error
5868c2ecf20Sopenharmony_ci */
5878c2ecf20Sopenharmony_cistatic int ti_msgmgr_queue_setup(int idx, struct device *dev,
5888c2ecf20Sopenharmony_ci				 struct device_node *np,
5898c2ecf20Sopenharmony_ci				 struct ti_msgmgr_inst *inst,
5908c2ecf20Sopenharmony_ci				 const struct ti_msgmgr_desc *d,
5918c2ecf20Sopenharmony_ci				 const struct ti_msgmgr_valid_queue_desc *qd,
5928c2ecf20Sopenharmony_ci				 struct ti_queue_inst *qinst,
5938c2ecf20Sopenharmony_ci				 struct mbox_chan *chan)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	char *dir;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	qinst->proxy_id = qd->proxy_id;
5988c2ecf20Sopenharmony_ci	qinst->queue_id = qd->queue_id;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	if (qinst->queue_id > d->queue_count) {
6018c2ecf20Sopenharmony_ci		dev_err(dev, "Queue Data [idx=%d] queuid %d > %d\n",
6028c2ecf20Sopenharmony_ci			idx, qinst->queue_id, d->queue_count);
6038c2ecf20Sopenharmony_ci		return -ERANGE;
6048c2ecf20Sopenharmony_ci	}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	if (d->is_sproxy) {
6078c2ecf20Sopenharmony_ci		qinst->queue_buff_start = inst->queue_proxy_region +
6088c2ecf20Sopenharmony_ci		    SPROXY_THREAD_DATA_OFFSET(qinst->proxy_id,
6098c2ecf20Sopenharmony_ci					      d->data_first_reg);
6108c2ecf20Sopenharmony_ci		qinst->queue_buff_end = inst->queue_proxy_region +
6118c2ecf20Sopenharmony_ci		    SPROXY_THREAD_DATA_OFFSET(qinst->proxy_id,
6128c2ecf20Sopenharmony_ci					      d->data_last_reg);
6138c2ecf20Sopenharmony_ci		qinst->queue_state = inst->queue_state_debug_region +
6148c2ecf20Sopenharmony_ci		    SPROXY_THREAD_STATUS_OFFSET(qinst->proxy_id);
6158c2ecf20Sopenharmony_ci		qinst->queue_ctrl = inst->queue_ctrl_region +
6168c2ecf20Sopenharmony_ci		    SPROXY_THREAD_CTRL_OFFSET(qinst->proxy_id);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci		/* XXX: DONOT read registers here!.. Some may be unusable */
6198c2ecf20Sopenharmony_ci		dir = "thr";
6208c2ecf20Sopenharmony_ci		snprintf(qinst->name, sizeof(qinst->name), "%s %s_%03d",
6218c2ecf20Sopenharmony_ci			 dev_name(dev), dir, qinst->proxy_id);
6228c2ecf20Sopenharmony_ci	} else {
6238c2ecf20Sopenharmony_ci		qinst->queue_buff_start = inst->queue_proxy_region +
6248c2ecf20Sopenharmony_ci		    Q_DATA_OFFSET(qinst->proxy_id, qinst->queue_id,
6258c2ecf20Sopenharmony_ci				  d->data_first_reg);
6268c2ecf20Sopenharmony_ci		qinst->queue_buff_end = inst->queue_proxy_region +
6278c2ecf20Sopenharmony_ci		    Q_DATA_OFFSET(qinst->proxy_id, qinst->queue_id,
6288c2ecf20Sopenharmony_ci				  d->data_last_reg);
6298c2ecf20Sopenharmony_ci		qinst->queue_state =
6308c2ecf20Sopenharmony_ci		    inst->queue_state_debug_region +
6318c2ecf20Sopenharmony_ci		    Q_STATE_OFFSET(qinst->queue_id);
6328c2ecf20Sopenharmony_ci		qinst->is_tx = qd->is_tx;
6338c2ecf20Sopenharmony_ci		dir = qinst->is_tx ? "tx" : "rx";
6348c2ecf20Sopenharmony_ci		snprintf(qinst->name, sizeof(qinst->name), "%s %s_%03d_%03d",
6358c2ecf20Sopenharmony_ci			 dev_name(dev), dir, qinst->queue_id, qinst->proxy_id);
6368c2ecf20Sopenharmony_ci	}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	qinst->chan = chan;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	/* Setup an error value for IRQ - Lazy allocation */
6418c2ecf20Sopenharmony_ci	qinst->irq = -EINVAL;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	chan->con_priv = qinst;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	dev_dbg(dev, "[%d] qidx=%d pidx=%d irq=%d q_s=%p q_e = %p\n",
6468c2ecf20Sopenharmony_ci		idx, qinst->queue_id, qinst->proxy_id, qinst->irq,
6478c2ecf20Sopenharmony_ci		qinst->queue_buff_start, qinst->queue_buff_end);
6488c2ecf20Sopenharmony_ci	return 0;
6498c2ecf20Sopenharmony_ci}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci/* Queue operations */
6528c2ecf20Sopenharmony_cistatic const struct mbox_chan_ops ti_msgmgr_chan_ops = {
6538c2ecf20Sopenharmony_ci	.startup = ti_msgmgr_queue_startup,
6548c2ecf20Sopenharmony_ci	.shutdown = ti_msgmgr_queue_shutdown,
6558c2ecf20Sopenharmony_ci	.peek_data = ti_msgmgr_queue_peek_data,
6568c2ecf20Sopenharmony_ci	.last_tx_done = ti_msgmgr_last_tx_done,
6578c2ecf20Sopenharmony_ci	.send_data = ti_msgmgr_send_data,
6588c2ecf20Sopenharmony_ci};
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci/* Keystone K2G SoC integration details */
6618c2ecf20Sopenharmony_cistatic const struct ti_msgmgr_valid_queue_desc k2g_valid_queues[] = {
6628c2ecf20Sopenharmony_ci	{.queue_id = 0, .proxy_id = 0, .is_tx = true,},
6638c2ecf20Sopenharmony_ci	{.queue_id = 1, .proxy_id = 0, .is_tx = true,},
6648c2ecf20Sopenharmony_ci	{.queue_id = 2, .proxy_id = 0, .is_tx = true,},
6658c2ecf20Sopenharmony_ci	{.queue_id = 3, .proxy_id = 0, .is_tx = true,},
6668c2ecf20Sopenharmony_ci	{.queue_id = 5, .proxy_id = 2, .is_tx = false,},
6678c2ecf20Sopenharmony_ci	{.queue_id = 56, .proxy_id = 1, .is_tx = true,},
6688c2ecf20Sopenharmony_ci	{.queue_id = 57, .proxy_id = 2, .is_tx = false,},
6698c2ecf20Sopenharmony_ci	{.queue_id = 58, .proxy_id = 3, .is_tx = true,},
6708c2ecf20Sopenharmony_ci	{.queue_id = 59, .proxy_id = 4, .is_tx = true,},
6718c2ecf20Sopenharmony_ci	{.queue_id = 60, .proxy_id = 5, .is_tx = true,},
6728c2ecf20Sopenharmony_ci	{.queue_id = 61, .proxy_id = 6, .is_tx = true,},
6738c2ecf20Sopenharmony_ci};
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_cistatic const struct ti_msgmgr_desc k2g_desc = {
6768c2ecf20Sopenharmony_ci	.queue_count = 64,
6778c2ecf20Sopenharmony_ci	.max_message_size = 64,
6788c2ecf20Sopenharmony_ci	.max_messages = 128,
6798c2ecf20Sopenharmony_ci	.data_region_name = "queue_proxy_region",
6808c2ecf20Sopenharmony_ci	.status_region_name = "queue_state_debug_region",
6818c2ecf20Sopenharmony_ci	.data_first_reg = 16,
6828c2ecf20Sopenharmony_ci	.data_last_reg = 31,
6838c2ecf20Sopenharmony_ci	.status_cnt_mask = Q_STATE_ENTRY_COUNT_MASK,
6848c2ecf20Sopenharmony_ci	.tx_polled = false,
6858c2ecf20Sopenharmony_ci	.valid_queues = k2g_valid_queues,
6868c2ecf20Sopenharmony_ci	.num_valid_queues = ARRAY_SIZE(k2g_valid_queues),
6878c2ecf20Sopenharmony_ci	.is_sproxy = false,
6888c2ecf20Sopenharmony_ci};
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_cistatic const struct ti_msgmgr_desc am654_desc = {
6918c2ecf20Sopenharmony_ci	.queue_count = 190,
6928c2ecf20Sopenharmony_ci	.num_valid_queues = 190,
6938c2ecf20Sopenharmony_ci	.max_message_size = 60,
6948c2ecf20Sopenharmony_ci	.data_region_name = "target_data",
6958c2ecf20Sopenharmony_ci	.status_region_name = "rt",
6968c2ecf20Sopenharmony_ci	.ctrl_region_name = "scfg",
6978c2ecf20Sopenharmony_ci	.data_first_reg = 0,
6988c2ecf20Sopenharmony_ci	.data_last_reg = 14,
6998c2ecf20Sopenharmony_ci	.status_cnt_mask = SPROXY_THREAD_STATUS_COUNT_MASK,
7008c2ecf20Sopenharmony_ci	.tx_polled = false,
7018c2ecf20Sopenharmony_ci	.is_sproxy = true,
7028c2ecf20Sopenharmony_ci};
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cistatic const struct of_device_id ti_msgmgr_of_match[] = {
7058c2ecf20Sopenharmony_ci	{.compatible = "ti,k2g-message-manager", .data = &k2g_desc},
7068c2ecf20Sopenharmony_ci	{.compatible = "ti,am654-secure-proxy", .data = &am654_desc},
7078c2ecf20Sopenharmony_ci	{ /* Sentinel */ }
7088c2ecf20Sopenharmony_ci};
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ti_msgmgr_of_match);
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic int ti_msgmgr_probe(struct platform_device *pdev)
7138c2ecf20Sopenharmony_ci{
7148c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
7158c2ecf20Sopenharmony_ci	const struct of_device_id *of_id;
7168c2ecf20Sopenharmony_ci	struct device_node *np;
7178c2ecf20Sopenharmony_ci	struct resource *res;
7188c2ecf20Sopenharmony_ci	const struct ti_msgmgr_desc *desc;
7198c2ecf20Sopenharmony_ci	struct ti_msgmgr_inst *inst;
7208c2ecf20Sopenharmony_ci	struct ti_queue_inst *qinst;
7218c2ecf20Sopenharmony_ci	struct mbox_controller *mbox;
7228c2ecf20Sopenharmony_ci	struct mbox_chan *chans;
7238c2ecf20Sopenharmony_ci	int queue_count;
7248c2ecf20Sopenharmony_ci	int i;
7258c2ecf20Sopenharmony_ci	int ret = -EINVAL;
7268c2ecf20Sopenharmony_ci	const struct ti_msgmgr_valid_queue_desc *queue_desc;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	if (!dev->of_node) {
7298c2ecf20Sopenharmony_ci		dev_err(dev, "no OF information\n");
7308c2ecf20Sopenharmony_ci		return -EINVAL;
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci	np = dev->of_node;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	of_id = of_match_device(ti_msgmgr_of_match, dev);
7358c2ecf20Sopenharmony_ci	if (!of_id) {
7368c2ecf20Sopenharmony_ci		dev_err(dev, "OF data missing\n");
7378c2ecf20Sopenharmony_ci		return -EINVAL;
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci	desc = of_id->data;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	inst = devm_kzalloc(dev, sizeof(*inst), GFP_KERNEL);
7428c2ecf20Sopenharmony_ci	if (!inst)
7438c2ecf20Sopenharmony_ci		return -ENOMEM;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	inst->dev = dev;
7468c2ecf20Sopenharmony_ci	inst->desc = desc;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
7498c2ecf20Sopenharmony_ci					   desc->data_region_name);
7508c2ecf20Sopenharmony_ci	inst->queue_proxy_region = devm_ioremap_resource(dev, res);
7518c2ecf20Sopenharmony_ci	if (IS_ERR(inst->queue_proxy_region))
7528c2ecf20Sopenharmony_ci		return PTR_ERR(inst->queue_proxy_region);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
7558c2ecf20Sopenharmony_ci					   desc->status_region_name);
7568c2ecf20Sopenharmony_ci	inst->queue_state_debug_region = devm_ioremap_resource(dev, res);
7578c2ecf20Sopenharmony_ci	if (IS_ERR(inst->queue_state_debug_region))
7588c2ecf20Sopenharmony_ci		return PTR_ERR(inst->queue_state_debug_region);
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	if (desc->is_sproxy) {
7618c2ecf20Sopenharmony_ci		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
7628c2ecf20Sopenharmony_ci						   desc->ctrl_region_name);
7638c2ecf20Sopenharmony_ci		inst->queue_ctrl_region = devm_ioremap_resource(dev, res);
7648c2ecf20Sopenharmony_ci		if (IS_ERR(inst->queue_ctrl_region))
7658c2ecf20Sopenharmony_ci			return PTR_ERR(inst->queue_ctrl_region);
7668c2ecf20Sopenharmony_ci	}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	dev_dbg(dev, "proxy region=%p, queue_state=%p\n",
7698c2ecf20Sopenharmony_ci		inst->queue_proxy_region, inst->queue_state_debug_region);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	queue_count = desc->num_valid_queues;
7728c2ecf20Sopenharmony_ci	if (!queue_count || queue_count > desc->queue_count) {
7738c2ecf20Sopenharmony_ci		dev_crit(dev, "Invalid Number of queues %d. Max %d\n",
7748c2ecf20Sopenharmony_ci			 queue_count, desc->queue_count);
7758c2ecf20Sopenharmony_ci		return -ERANGE;
7768c2ecf20Sopenharmony_ci	}
7778c2ecf20Sopenharmony_ci	inst->num_valid_queues = queue_count;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	qinst = devm_kcalloc(dev, queue_count, sizeof(*qinst), GFP_KERNEL);
7808c2ecf20Sopenharmony_ci	if (!qinst)
7818c2ecf20Sopenharmony_ci		return -ENOMEM;
7828c2ecf20Sopenharmony_ci	inst->qinsts = qinst;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	chans = devm_kcalloc(dev, queue_count, sizeof(*chans), GFP_KERNEL);
7858c2ecf20Sopenharmony_ci	if (!chans)
7868c2ecf20Sopenharmony_ci		return -ENOMEM;
7878c2ecf20Sopenharmony_ci	inst->chans = chans;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	if (desc->is_sproxy) {
7908c2ecf20Sopenharmony_ci		struct ti_msgmgr_valid_queue_desc sproxy_desc;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci		/* All proxies may be valid in Secure Proxy instance */
7938c2ecf20Sopenharmony_ci		for (i = 0; i < queue_count; i++, qinst++, chans++) {
7948c2ecf20Sopenharmony_ci			sproxy_desc.queue_id = 0;
7958c2ecf20Sopenharmony_ci			sproxy_desc.proxy_id = i;
7968c2ecf20Sopenharmony_ci			ret = ti_msgmgr_queue_setup(i, dev, np, inst,
7978c2ecf20Sopenharmony_ci						    desc, &sproxy_desc, qinst,
7988c2ecf20Sopenharmony_ci						    chans);
7998c2ecf20Sopenharmony_ci			if (ret)
8008c2ecf20Sopenharmony_ci				return ret;
8018c2ecf20Sopenharmony_ci		}
8028c2ecf20Sopenharmony_ci	} else {
8038c2ecf20Sopenharmony_ci		/* Only Some proxies are valid in Message Manager */
8048c2ecf20Sopenharmony_ci		for (i = 0, queue_desc = desc->valid_queues;
8058c2ecf20Sopenharmony_ci		     i < queue_count; i++, qinst++, chans++, queue_desc++) {
8068c2ecf20Sopenharmony_ci			ret = ti_msgmgr_queue_setup(i, dev, np, inst,
8078c2ecf20Sopenharmony_ci						    desc, queue_desc, qinst,
8088c2ecf20Sopenharmony_ci						    chans);
8098c2ecf20Sopenharmony_ci			if (ret)
8108c2ecf20Sopenharmony_ci				return ret;
8118c2ecf20Sopenharmony_ci		}
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	mbox = &inst->mbox;
8158c2ecf20Sopenharmony_ci	mbox->dev = dev;
8168c2ecf20Sopenharmony_ci	mbox->ops = &ti_msgmgr_chan_ops;
8178c2ecf20Sopenharmony_ci	mbox->chans = inst->chans;
8188c2ecf20Sopenharmony_ci	mbox->num_chans = inst->num_valid_queues;
8198c2ecf20Sopenharmony_ci	mbox->txdone_irq = false;
8208c2ecf20Sopenharmony_ci	mbox->txdone_poll = desc->tx_polled;
8218c2ecf20Sopenharmony_ci	if (desc->tx_polled)
8228c2ecf20Sopenharmony_ci		mbox->txpoll_period = desc->tx_poll_timeout_ms;
8238c2ecf20Sopenharmony_ci	mbox->of_xlate = ti_msgmgr_of_xlate;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, inst);
8268c2ecf20Sopenharmony_ci	ret = devm_mbox_controller_register(dev, mbox);
8278c2ecf20Sopenharmony_ci	if (ret)
8288c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to register mbox_controller(%d)\n", ret);
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	return ret;
8318c2ecf20Sopenharmony_ci}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_cistatic struct platform_driver ti_msgmgr_driver = {
8348c2ecf20Sopenharmony_ci	.probe = ti_msgmgr_probe,
8358c2ecf20Sopenharmony_ci	.driver = {
8368c2ecf20Sopenharmony_ci		   .name = "ti-msgmgr",
8378c2ecf20Sopenharmony_ci		   .of_match_table = of_match_ptr(ti_msgmgr_of_match),
8388c2ecf20Sopenharmony_ci	},
8398c2ecf20Sopenharmony_ci};
8408c2ecf20Sopenharmony_cimodule_platform_driver(ti_msgmgr_driver);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
8438c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI message manager driver");
8448c2ecf20Sopenharmony_ciMODULE_AUTHOR("Nishanth Menon");
8458c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:ti-msgmgr");
846