.. | .. |
---|
9 | 9 | #include <linux/arm-smccc.h> |
---|
10 | 10 | #include <linux/device.h> |
---|
11 | 11 | #include <linux/err.h> |
---|
| 12 | +#include <linux/interrupt.h> |
---|
12 | 13 | #include <linux/mutex.h> |
---|
13 | 14 | #include <linux/of.h> |
---|
14 | 15 | #include <linux/of_address.h> |
---|
| 16 | +#include <linux/of_irq.h> |
---|
15 | 17 | #include <linux/slab.h> |
---|
16 | 18 | |
---|
17 | 19 | #include "common.h" |
---|
.. | .. |
---|
23 | 25 | * @shmem: Transmit/Receive shared memory area |
---|
24 | 26 | * @shmem_lock: Lock to protect access to Tx/Rx shared memory area |
---|
25 | 27 | * @func_id: smc/hvc call function id |
---|
| 28 | + * @irq: Optional; employed when platforms indicates msg completion by intr. |
---|
| 29 | + * @tx_complete: Optional, employed only when irq is valid. |
---|
26 | 30 | */ |
---|
27 | 31 | |
---|
28 | 32 | struct scmi_smc { |
---|
.. | .. |
---|
30 | 34 | struct scmi_shared_mem __iomem *shmem; |
---|
31 | 35 | struct mutex shmem_lock; |
---|
32 | 36 | u32 func_id; |
---|
| 37 | + int irq; |
---|
| 38 | + struct completion tx_complete; |
---|
33 | 39 | }; |
---|
| 40 | + |
---|
| 41 | +static irqreturn_t smc_msg_done_isr(int irq, void *data) |
---|
| 42 | +{ |
---|
| 43 | + struct scmi_smc *scmi_info = data; |
---|
| 44 | + |
---|
| 45 | + complete(&scmi_info->tx_complete); |
---|
| 46 | + |
---|
| 47 | + return IRQ_HANDLED; |
---|
| 48 | +} |
---|
34 | 49 | |
---|
35 | 50 | static bool smc_chan_available(struct device *dev, int idx) |
---|
36 | 51 | { |
---|
.. | .. |
---|
51 | 66 | struct resource res; |
---|
52 | 67 | struct device_node *np; |
---|
53 | 68 | u32 func_id; |
---|
54 | | - int ret; |
---|
| 69 | + int ret, irq; |
---|
55 | 70 | |
---|
56 | 71 | if (!tx) |
---|
57 | 72 | return -ENODEV; |
---|
.. | .. |
---|
78 | 93 | ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id); |
---|
79 | 94 | if (ret < 0) |
---|
80 | 95 | return ret; |
---|
| 96 | + |
---|
| 97 | + /* |
---|
| 98 | + * If there is an interrupt named "a2p", then the service and |
---|
| 99 | + * completion of a message is signaled by an interrupt rather than by |
---|
| 100 | + * the return of the SMC call. |
---|
| 101 | + */ |
---|
| 102 | + irq = of_irq_get_byname(cdev->of_node, "a2p"); |
---|
| 103 | + if (irq > 0) { |
---|
| 104 | + ret = devm_request_irq(dev, irq, smc_msg_done_isr, |
---|
| 105 | + IRQF_NO_SUSPEND, |
---|
| 106 | + dev_name(dev), scmi_info); |
---|
| 107 | + if (ret) { |
---|
| 108 | + dev_err(dev, "failed to setup SCMI smc irq\n"); |
---|
| 109 | + return ret; |
---|
| 110 | + } |
---|
| 111 | + init_completion(&scmi_info->tx_complete); |
---|
| 112 | + scmi_info->irq = irq; |
---|
| 113 | + } |
---|
81 | 114 | |
---|
82 | 115 | scmi_info->func_id = func_id; |
---|
83 | 116 | scmi_info->cinfo = cinfo; |
---|
.. | .. |
---|
110 | 143 | |
---|
111 | 144 | shmem_tx_prepare(scmi_info->shmem, xfer); |
---|
112 | 145 | |
---|
| 146 | + if (scmi_info->irq) |
---|
| 147 | + reinit_completion(&scmi_info->tx_complete); |
---|
| 148 | + |
---|
113 | 149 | arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res); |
---|
| 150 | + |
---|
| 151 | + if (scmi_info->irq) |
---|
| 152 | + wait_for_completion(&scmi_info->tx_complete); |
---|
| 153 | + |
---|
114 | 154 | scmi_rx_callback(scmi_info->cinfo, shmem_read_header(scmi_info->shmem)); |
---|
115 | 155 | |
---|
116 | 156 | mutex_unlock(&scmi_info->shmem_lock); |
---|
.. | .. |
---|
137 | 177 | return shmem_poll_done(scmi_info->shmem, xfer); |
---|
138 | 178 | } |
---|
139 | 179 | |
---|
140 | | -static struct scmi_transport_ops scmi_smc_ops = { |
---|
| 180 | +static const struct scmi_transport_ops scmi_smc_ops = { |
---|
141 | 181 | .chan_available = smc_chan_available, |
---|
142 | 182 | .chan_setup = smc_chan_setup, |
---|
143 | 183 | .chan_free = smc_chan_free, |
---|