0001
0002
0003
0004
0005 #include <asm/barrier.h>
0006 #include <linux/clk.h>
0007 #include <linux/err.h>
0008 #include <linux/io.h>
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/remoteproc/mtk_scp.h>
0013
0014 #include "mtk_common.h"
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 int scp_ipi_register(struct mtk_scp *scp,
0029 u32 id,
0030 scp_ipi_handler_t handler,
0031 void *priv)
0032 {
0033 if (!scp)
0034 return -EPROBE_DEFER;
0035
0036 if (WARN_ON(id >= SCP_IPI_MAX) || WARN_ON(handler == NULL))
0037 return -EINVAL;
0038
0039 scp_ipi_lock(scp, id);
0040 scp->ipi_desc[id].handler = handler;
0041 scp->ipi_desc[id].priv = priv;
0042 scp_ipi_unlock(scp, id);
0043
0044 return 0;
0045 }
0046 EXPORT_SYMBOL_GPL(scp_ipi_register);
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056 void scp_ipi_unregister(struct mtk_scp *scp, u32 id)
0057 {
0058 if (!scp)
0059 return;
0060
0061 if (WARN_ON(id >= SCP_IPI_MAX))
0062 return;
0063
0064 scp_ipi_lock(scp, id);
0065 scp->ipi_desc[id].handler = NULL;
0066 scp->ipi_desc[id].priv = NULL;
0067 scp_ipi_unlock(scp, id);
0068 }
0069 EXPORT_SYMBOL_GPL(scp_ipi_unregister);
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 void scp_memcpy_aligned(void __iomem *dst, const void *src, unsigned int len)
0083 {
0084 void __iomem *ptr;
0085 u32 val;
0086 unsigned int i = 0, remain;
0087
0088 if (!IS_ALIGNED((unsigned long)dst, 4)) {
0089 ptr = (void __iomem *)ALIGN_DOWN((unsigned long)dst, 4);
0090 i = 4 - (dst - ptr);
0091 val = readl_relaxed(ptr);
0092 memcpy((u8 *)&val + (4 - i), src, i);
0093 writel_relaxed(val, ptr);
0094 }
0095
0096 __iowrite32_copy(dst + i, src + i, (len - i) / 4);
0097 remain = (len - i) % 4;
0098
0099 if (remain > 0) {
0100 val = readl_relaxed(dst + len - remain);
0101 memcpy(&val, src + len - remain, remain);
0102 writel_relaxed(val, dst + len - remain);
0103 }
0104 }
0105 EXPORT_SYMBOL_GPL(scp_memcpy_aligned);
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115 void scp_ipi_lock(struct mtk_scp *scp, u32 id)
0116 {
0117 if (WARN_ON(id >= SCP_IPI_MAX))
0118 return;
0119 mutex_lock(&scp->ipi_desc[id].lock);
0120 }
0121 EXPORT_SYMBOL_GPL(scp_ipi_lock);
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131 void scp_ipi_unlock(struct mtk_scp *scp, u32 id)
0132 {
0133 if (WARN_ON(id >= SCP_IPI_MAX))
0134 return;
0135 mutex_unlock(&scp->ipi_desc[id].lock);
0136 }
0137 EXPORT_SYMBOL_GPL(scp_ipi_unlock);
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155 int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
0156 unsigned int wait)
0157 {
0158 struct mtk_share_obj __iomem *send_obj = scp->send_buf;
0159 unsigned long timeout;
0160 int ret;
0161
0162 if (WARN_ON(id <= SCP_IPI_INIT) || WARN_ON(id >= SCP_IPI_MAX) ||
0163 WARN_ON(id == SCP_IPI_NS_SERVICE) ||
0164 WARN_ON(len > sizeof(send_obj->share_buf)) || WARN_ON(!buf))
0165 return -EINVAL;
0166
0167 mutex_lock(&scp->send_lock);
0168
0169 ret = clk_prepare_enable(scp->clk);
0170 if (ret) {
0171 dev_err(scp->dev, "failed to enable clock\n");
0172 goto unlock_mutex;
0173 }
0174
0175
0176 timeout = jiffies + msecs_to_jiffies(2000);
0177 do {
0178 if (time_after(jiffies, timeout)) {
0179 dev_err(scp->dev, "%s: IPI timeout!\n", __func__);
0180 ret = -ETIMEDOUT;
0181 goto clock_disable;
0182 }
0183 } while (readl(scp->reg_base + scp->data->host_to_scp_reg));
0184
0185 scp_memcpy_aligned(send_obj->share_buf, buf, len);
0186
0187 writel(len, &send_obj->len);
0188 writel(id, &send_obj->id);
0189
0190 scp->ipi_id_ack[id] = false;
0191
0192 writel(scp->data->host_to_scp_int_bit,
0193 scp->reg_base + scp->data->host_to_scp_reg);
0194
0195 if (wait) {
0196
0197 timeout = msecs_to_jiffies(wait);
0198 ret = wait_event_timeout(scp->ack_wq,
0199 scp->ipi_id_ack[id],
0200 timeout);
0201 scp->ipi_id_ack[id] = false;
0202 if (WARN(!ret, "scp ipi %d ack time out !", id))
0203 ret = -EIO;
0204 else
0205 ret = 0;
0206 }
0207
0208 clock_disable:
0209 clk_disable_unprepare(scp->clk);
0210 unlock_mutex:
0211 mutex_unlock(&scp->send_lock);
0212
0213 return ret;
0214 }
0215 EXPORT_SYMBOL_GPL(scp_ipi_send);
0216
0217 MODULE_LICENSE("GPL v2");
0218 MODULE_DESCRIPTION("MediaTek scp IPI interface");