diff options
Diffstat (limited to 'drivers/mailbox/ti-msgmgr.c')
| -rw-r--r-- | drivers/mailbox/ti-msgmgr.c | 93 | 
1 files changed, 91 insertions, 2 deletions
diff --git a/drivers/mailbox/ti-msgmgr.c b/drivers/mailbox/ti-msgmgr.c index f860cd0c907a..ddac423ac1a9 100644 --- a/drivers/mailbox/ti-msgmgr.c +++ b/drivers/mailbox/ti-msgmgr.c @@ -2,7 +2,7 @@  /*   * Texas Instruments' Message Manager Driver   * - * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2015-2022 Texas Instruments Incorporated - https://www.ti.com/   *	Nishanth Menon   */ @@ -11,6 +11,7 @@  #include <linux/device.h>  #include <linux/interrupt.h>  #include <linux/io.h> +#include <linux/iopoll.h>  #include <linux/kernel.h>  #include <linux/mailbox_controller.h>  #include <linux/module.h> @@ -100,6 +101,7 @@ struct ti_msgmgr_desc {   * @queue_ctrl: Queue Control register   * @chan:	Mailbox channel   * @rx_buff:	Receive buffer pointer allocated at probe, max_message_size + * @polled_rx_mode: Use polling for rx instead of interrupts   */  struct ti_queue_inst {  	char name[30]; @@ -113,6 +115,7 @@ struct ti_queue_inst {  	void __iomem *queue_ctrl;  	struct mbox_chan *chan;  	u32 *rx_buff; +	bool polled_rx_mode;  };  /** @@ -237,6 +240,26 @@ static int ti_msgmgr_queue_rx_data(struct mbox_chan *chan, struct ti_queue_inst  	return 0;  } +static int ti_msgmgr_queue_rx_poll_timeout(struct mbox_chan *chan, int timeout_us) +{ +	struct device *dev = chan->mbox->dev; +	struct ti_msgmgr_inst *inst = dev_get_drvdata(dev); +	struct ti_queue_inst *qinst = chan->con_priv; +	const struct ti_msgmgr_desc *desc = inst->desc; +	int msg_count; +	int ret; + +	ret = readl_poll_timeout_atomic(qinst->queue_state, msg_count, +					(msg_count & desc->status_cnt_mask), +					10, timeout_us); +	if (ret != 0) +		return ret; + +	ti_msgmgr_queue_rx_data(chan, qinst, desc); + +	return 0; +} +  /**   * ti_msgmgr_queue_rx_interrupt() - Interrupt handler for receive Queue   * @irq:	Interrupt number @@ -346,6 +369,17 @@ static bool ti_msgmgr_last_tx_done(struct mbox_chan *chan)  	return msg_count ? false : true;  } +static bool ti_msgmgr_chan_has_polled_queue_rx(struct mbox_chan *chan) +{ +	struct ti_queue_inst *qinst; + +	if (!chan) +		return false; + +	qinst = chan->con_priv; +	return qinst->polled_rx_mode; +} +  /**   * ti_msgmgr_send_data() - Send data   * @chan:	Channel Pointer @@ -363,6 +397,7 @@ static int ti_msgmgr_send_data(struct mbox_chan *chan, void *data)  	struct ti_msgmgr_message *message = data;  	void __iomem *data_reg;  	u32 *word_data; +	int ret = 0;  	if (WARN_ON(!inst)) {  		dev_err(dev, "no platform drv data??\n"); @@ -404,7 +439,12 @@ static int ti_msgmgr_send_data(struct mbox_chan *chan, void *data)  	if (data_reg <= qinst->queue_buff_end)  		writel(0, qinst->queue_buff_end); -	return 0; +	/* If we are in polled mode, wait for a response before proceeding */ +	if (ti_msgmgr_chan_has_polled_queue_rx(message->chan_rx)) +		ret = ti_msgmgr_queue_rx_poll_timeout(message->chan_rx, +						      message->timeout_rx_ms * 1000); + +	return ret;  }  /** @@ -652,6 +692,54 @@ static int ti_msgmgr_queue_setup(int idx, struct device *dev,  	return 0;  } +static int ti_msgmgr_queue_rx_set_polled_mode(struct ti_queue_inst *qinst, bool enable) +{ +	if (enable) { +		disable_irq(qinst->irq); +		qinst->polled_rx_mode = true; +	} else { +		enable_irq(qinst->irq); +		qinst->polled_rx_mode = false; +	} + +	return 0; +} + +static int ti_msgmgr_suspend(struct device *dev) +{ +	struct ti_msgmgr_inst *inst = dev_get_drvdata(dev); +	struct ti_queue_inst *qinst; +	int i; + +	/* +	 * We must switch operation to polled mode now as drivers and the genpd +	 * layer may make late TI SCI calls to change clock and device states +	 * from the noirq phase of suspend. +	 */ +	for (qinst = inst->qinsts, i = 0; i < inst->num_valid_queues; qinst++, i++) { +		if (!qinst->is_tx) +			ti_msgmgr_queue_rx_set_polled_mode(qinst, true); +	} + +	return 0; +} + +static int ti_msgmgr_resume(struct device *dev) +{ +	struct ti_msgmgr_inst *inst = dev_get_drvdata(dev); +	struct ti_queue_inst *qinst; +	int i; + +	for (qinst = inst->qinsts, i = 0; i < inst->num_valid_queues; qinst++, i++) { +		if (!qinst->is_tx) +			ti_msgmgr_queue_rx_set_polled_mode(qinst, false); +	} + +	return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(ti_msgmgr_pm_ops, ti_msgmgr_suspend, ti_msgmgr_resume); +  /* Queue operations */  static const struct mbox_chan_ops ti_msgmgr_chan_ops = {  	.startup = ti_msgmgr_queue_startup, @@ -839,6 +927,7 @@ static struct platform_driver ti_msgmgr_driver = {  	.driver = {  		   .name = "ti-msgmgr",  		   .of_match_table = of_match_ptr(ti_msgmgr_of_match), +		   .pm = &ti_msgmgr_pm_ops,  	},  };  module_platform_driver(ti_msgmgr_driver);  | 
