Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2016-2017, Linaro Ltd
0004  */
0005 
0006 #include <linux/idr.h>
0007 #include <linux/interrupt.h>
0008 #include <linux/io.h>
0009 #include <linux/list.h>
0010 #include <linux/mfd/syscon.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/of_address.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/regmap.h>
0016 #include <linux/rpmsg.h>
0017 #include <linux/slab.h>
0018 #include <linux/workqueue.h>
0019 #include <linux/mailbox_client.h>
0020 
0021 #include "rpmsg_internal.h"
0022 #include "qcom_glink_native.h"
0023 
0024 #define RPM_TOC_SIZE        256
0025 #define RPM_TOC_MAGIC       0x67727430 /* grt0 */
0026 #define RPM_TOC_MAX_ENTRIES ((RPM_TOC_SIZE - sizeof(struct rpm_toc)) / \
0027                  sizeof(struct rpm_toc_entry))
0028 
0029 #define RPM_TX_FIFO_ID      0x61703272 /* ap2r */
0030 #define RPM_RX_FIFO_ID      0x72326170 /* r2ap */
0031 
0032 #define to_rpm_pipe(p) container_of(p, struct glink_rpm_pipe, native)
0033 
0034 struct rpm_toc_entry {
0035     __le32 id;
0036     __le32 offset;
0037     __le32 size;
0038 } __packed;
0039 
0040 struct rpm_toc {
0041     __le32 magic;
0042     __le32 count;
0043 
0044     struct rpm_toc_entry entries[];
0045 } __packed;
0046 
0047 struct glink_rpm_pipe {
0048     struct qcom_glink_pipe native;
0049 
0050     void __iomem *tail;
0051     void __iomem *head;
0052 
0053     void __iomem *fifo;
0054 };
0055 
0056 static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)
0057 {
0058     struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
0059     unsigned int head;
0060     unsigned int tail;
0061 
0062     head = readl(pipe->head);
0063     tail = readl(pipe->tail);
0064 
0065     if (head < tail)
0066         return pipe->native.length - tail + head;
0067     else
0068         return head - tail;
0069 }
0070 
0071 static void glink_rpm_rx_peak(struct qcom_glink_pipe *glink_pipe,
0072                   void *data, unsigned int offset, size_t count)
0073 {
0074     struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
0075     unsigned int tail;
0076     size_t len;
0077 
0078     tail = readl(pipe->tail);
0079     tail += offset;
0080     if (tail >= pipe->native.length)
0081         tail -= pipe->native.length;
0082 
0083     len = min_t(size_t, count, pipe->native.length - tail);
0084     if (len) {
0085         __ioread32_copy(data, pipe->fifo + tail,
0086                 len / sizeof(u32));
0087     }
0088 
0089     if (len != count) {
0090         __ioread32_copy(data + len, pipe->fifo,
0091                 (count - len) / sizeof(u32));
0092     }
0093 }
0094 
0095 static void glink_rpm_rx_advance(struct qcom_glink_pipe *glink_pipe,
0096                  size_t count)
0097 {
0098     struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
0099     unsigned int tail;
0100 
0101     tail = readl(pipe->tail);
0102 
0103     tail += count;
0104     if (tail >= pipe->native.length)
0105         tail -= pipe->native.length;
0106 
0107     writel(tail, pipe->tail);
0108 }
0109 
0110 static size_t glink_rpm_tx_avail(struct qcom_glink_pipe *glink_pipe)
0111 {
0112     struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
0113     unsigned int head;
0114     unsigned int tail;
0115 
0116     head = readl(pipe->head);
0117     tail = readl(pipe->tail);
0118 
0119     if (tail <= head)
0120         return pipe->native.length - head + tail;
0121     else
0122         return tail - head;
0123 }
0124 
0125 static unsigned int glink_rpm_tx_write_one(struct glink_rpm_pipe *pipe,
0126                        unsigned int head,
0127                        const void *data, size_t count)
0128 {
0129     size_t len;
0130 
0131     len = min_t(size_t, count, pipe->native.length - head);
0132     if (len) {
0133         __iowrite32_copy(pipe->fifo + head, data,
0134                  len / sizeof(u32));
0135     }
0136 
0137     if (len != count) {
0138         __iowrite32_copy(pipe->fifo, data + len,
0139                  (count - len) / sizeof(u32));
0140     }
0141 
0142     head += count;
0143     if (head >= pipe->native.length)
0144         head -= pipe->native.length;
0145 
0146     return head;
0147 }
0148 
0149 static void glink_rpm_tx_write(struct qcom_glink_pipe *glink_pipe,
0150                    const void *hdr, size_t hlen,
0151                    const void *data, size_t dlen)
0152 {
0153     struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
0154     size_t tlen = hlen + dlen;
0155     size_t aligned_dlen;
0156     unsigned int head;
0157     char padding[8] = {0};
0158     size_t pad;
0159 
0160     /* Header length comes from glink native and is always 4 byte aligned */
0161     if (WARN(hlen % 4, "Glink Header length must be 4 bytes aligned\n"))
0162         return;
0163 
0164     /*
0165      * Move the unaligned tail of the message to the padding chunk, to
0166      * ensure word aligned accesses
0167      */
0168     aligned_dlen = ALIGN_DOWN(dlen, 4);
0169     if (aligned_dlen != dlen)
0170         memcpy(padding, data + aligned_dlen, dlen - aligned_dlen);
0171 
0172     head = readl(pipe->head);
0173     head = glink_rpm_tx_write_one(pipe, head, hdr, hlen);
0174     head = glink_rpm_tx_write_one(pipe, head, data, aligned_dlen);
0175 
0176     pad = ALIGN(tlen, 8) - ALIGN_DOWN(tlen, 4);
0177     if (pad)
0178         head = glink_rpm_tx_write_one(pipe, head, padding, pad);
0179     writel(head, pipe->head);
0180 }
0181 
0182 static int glink_rpm_parse_toc(struct device *dev,
0183                    void __iomem *msg_ram,
0184                    size_t msg_ram_size,
0185                    struct glink_rpm_pipe *rx,
0186                    struct glink_rpm_pipe *tx)
0187 {
0188     struct rpm_toc *toc;
0189     int num_entries;
0190     unsigned int id;
0191     size_t offset;
0192     size_t size;
0193     void *buf;
0194     int i;
0195 
0196     buf = kzalloc(RPM_TOC_SIZE, GFP_KERNEL);
0197     if (!buf)
0198         return -ENOMEM;
0199 
0200     __ioread32_copy(buf, msg_ram + msg_ram_size - RPM_TOC_SIZE,
0201             RPM_TOC_SIZE / sizeof(u32));
0202 
0203     toc = buf;
0204 
0205     if (le32_to_cpu(toc->magic) != RPM_TOC_MAGIC) {
0206         dev_err(dev, "RPM TOC has invalid magic\n");
0207         goto err_inval;
0208     }
0209 
0210     num_entries = le32_to_cpu(toc->count);
0211     if (num_entries > RPM_TOC_MAX_ENTRIES) {
0212         dev_err(dev, "Invalid number of toc entries\n");
0213         goto err_inval;
0214     }
0215 
0216     for (i = 0; i < num_entries; i++) {
0217         id = le32_to_cpu(toc->entries[i].id);
0218         offset = le32_to_cpu(toc->entries[i].offset);
0219         size = le32_to_cpu(toc->entries[i].size);
0220 
0221         if (offset > msg_ram_size || offset + size > msg_ram_size) {
0222             dev_err(dev, "TOC entry with invalid size\n");
0223             continue;
0224         }
0225 
0226         switch (id) {
0227         case RPM_RX_FIFO_ID:
0228             rx->native.length = size;
0229 
0230             rx->tail = msg_ram + offset;
0231             rx->head = msg_ram + offset + sizeof(u32);
0232             rx->fifo = msg_ram + offset + 2 * sizeof(u32);
0233             break;
0234         case RPM_TX_FIFO_ID:
0235             tx->native.length = size;
0236 
0237             tx->tail = msg_ram + offset;
0238             tx->head = msg_ram + offset + sizeof(u32);
0239             tx->fifo = msg_ram + offset + 2 * sizeof(u32);
0240             break;
0241         }
0242     }
0243 
0244     if (!rx->fifo || !tx->fifo) {
0245         dev_err(dev, "Unable to find rx and tx descriptors\n");
0246         goto err_inval;
0247     }
0248 
0249     kfree(buf);
0250     return 0;
0251 
0252 err_inval:
0253     kfree(buf);
0254     return -EINVAL;
0255 }
0256 
0257 static int glink_rpm_probe(struct platform_device *pdev)
0258 {
0259     struct qcom_glink *glink;
0260     struct glink_rpm_pipe *rx_pipe;
0261     struct glink_rpm_pipe *tx_pipe;
0262     struct device_node *np;
0263     void __iomem *msg_ram;
0264     size_t msg_ram_size;
0265     struct device *dev = &pdev->dev;
0266     struct resource r;
0267     int ret;
0268 
0269     rx_pipe = devm_kzalloc(&pdev->dev, sizeof(*rx_pipe), GFP_KERNEL);
0270     tx_pipe = devm_kzalloc(&pdev->dev, sizeof(*tx_pipe), GFP_KERNEL);
0271     if (!rx_pipe || !tx_pipe)
0272         return -ENOMEM;
0273 
0274     np = of_parse_phandle(dev->of_node, "qcom,rpm-msg-ram", 0);
0275     ret = of_address_to_resource(np, 0, &r);
0276     of_node_put(np);
0277     if (ret)
0278         return ret;
0279 
0280     msg_ram = devm_ioremap(dev, r.start, resource_size(&r));
0281     msg_ram_size = resource_size(&r);
0282     if (!msg_ram)
0283         return -ENOMEM;
0284 
0285     ret = glink_rpm_parse_toc(dev, msg_ram, msg_ram_size,
0286                   rx_pipe, tx_pipe);
0287     if (ret)
0288         return ret;
0289 
0290     /* Pipe specific accessors */
0291     rx_pipe->native.avail = glink_rpm_rx_avail;
0292     rx_pipe->native.peak = glink_rpm_rx_peak;
0293     rx_pipe->native.advance = glink_rpm_rx_advance;
0294     tx_pipe->native.avail = glink_rpm_tx_avail;
0295     tx_pipe->native.write = glink_rpm_tx_write;
0296 
0297     writel(0, tx_pipe->head);
0298     writel(0, rx_pipe->tail);
0299 
0300     glink = qcom_glink_native_probe(&pdev->dev,
0301                     0,
0302                     &rx_pipe->native,
0303                     &tx_pipe->native,
0304                     true);
0305     if (IS_ERR(glink))
0306         return PTR_ERR(glink);
0307 
0308     platform_set_drvdata(pdev, glink);
0309 
0310     return 0;
0311 }
0312 
0313 static int glink_rpm_remove(struct platform_device *pdev)
0314 {
0315     struct qcom_glink *glink = platform_get_drvdata(pdev);
0316 
0317     qcom_glink_native_remove(glink);
0318 
0319     return 0;
0320 }
0321 
0322 static const struct of_device_id glink_rpm_of_match[] = {
0323     { .compatible = "qcom,glink-rpm" },
0324     {}
0325 };
0326 MODULE_DEVICE_TABLE(of, glink_rpm_of_match);
0327 
0328 static struct platform_driver glink_rpm_driver = {
0329     .probe = glink_rpm_probe,
0330     .remove = glink_rpm_remove,
0331     .driver = {
0332         .name = "qcom_glink_rpm",
0333         .of_match_table = glink_rpm_of_match,
0334     },
0335 };
0336 
0337 static int __init glink_rpm_init(void)
0338 {
0339     return platform_driver_register(&glink_rpm_driver);
0340 }
0341 subsys_initcall(glink_rpm_init);
0342 
0343 static void __exit glink_rpm_exit(void)
0344 {
0345     platform_driver_unregister(&glink_rpm_driver);
0346 }
0347 module_exit(glink_rpm_exit);
0348 
0349 MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@linaro.org>");
0350 MODULE_DESCRIPTION("Qualcomm GLINK RPM driver");
0351 MODULE_LICENSE("GPL v2");