linux/drivers/remoteproc/zynq_remoteproc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Zynq Remote Processor driver
   4 *
   5 * Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
   6 * Copyright (C) 2012 PetaLogix
   7 *
   8 * Based on origin OMAP Remote Processor driver
   9 *
  10 * Copyright (C) 2011 Texas Instruments, Inc.
  11 * Copyright (C) 2011 Google, Inc.
  12 */
  13
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/err.h>
  17#include <linux/platform_device.h>
  18#include <linux/dma-mapping.h>
  19#include <linux/remoteproc.h>
  20#include <linux/interrupt.h>
  21#include <linux/of_address.h>
  22#include <linux/of_irq.h>
  23#include <linux/of_reserved_mem.h>
  24#include <linux/smp.h>
  25#include <linux/irqchip/arm-gic.h>
  26#include <asm/outercache.h>
  27#include <linux/slab.h>
  28#include <linux/cpu.h>
  29#include <linux/genalloc.h>
  30#include <../../arch/arm/mach-zynq/common.h>
  31
  32#include "remoteproc_internal.h"
  33
  34#define MAX_NUM_VRINGS 2
  35#define NOTIFYID_ANY (-1)
  36/* Maximum on chip memories used by the driver*/
  37#define MAX_ON_CHIP_MEMS        32
  38
  39/* Structure for storing IRQs */
  40struct irq_list {
  41        int irq;
  42        struct list_head list;
  43};
  44
  45/* Structure for IPIs */
  46struct ipi_info {
  47        u32 irq;
  48        u32 notifyid;
  49        bool pending;
  50};
  51
  52/**
  53 * struct zynq_mem_res - zynq memory resource for firmware memory
  54 * @res: memory resource
  55 * @node: list node
  56 */
  57struct zynq_mem_res {
  58        struct resource res;
  59        struct list_head node;
  60};
  61
  62/**
  63 * struct zynq_rproc_data - zynq rproc private data
  64 * @irqs: inter processor soft IRQs
  65 * @rproc: pointer to remoteproc instance
  66 * @ipis: interrupt processor interrupts statistics
  67 * @fw_mems: list of firmware memories
  68 */
  69struct zynq_rproc_pdata {
  70        struct irq_list irqs;
  71        struct rproc *rproc;
  72        struct ipi_info ipis[MAX_NUM_VRINGS];
  73        struct list_head fw_mems;
  74};
  75
  76static bool autoboot __read_mostly;
  77
  78/* Store rproc for IPI handler */
  79static struct rproc *rproc;
  80static struct work_struct workqueue;
  81
  82static void handle_event(struct work_struct *work)
  83{
  84        struct zynq_rproc_pdata *local = rproc->priv;
  85
  86        if (rproc_vq_interrupt(local->rproc, local->ipis[0].notifyid) ==
  87                                IRQ_NONE)
  88                dev_dbg(rproc->dev.parent, "no message found in vqid 0\n");
  89}
  90
  91static void ipi_kick(void)
  92{
  93        dev_dbg(rproc->dev.parent, "KICK Linux because of pending message\n");
  94        schedule_work(&workqueue);
  95}
  96
  97static void kick_pending_ipi(struct rproc *rproc)
  98{
  99        struct zynq_rproc_pdata *local = rproc->priv;
 100        int i;
 101
 102        for (i = 0; i < MAX_NUM_VRINGS; i++) {
 103                /* Send swirq to firmware */
 104                if (local->ipis[i].pending) {
 105                        gic_raise_softirq(cpumask_of(1),
 106                                          local->ipis[i].irq);
 107                        local->ipis[i].pending = false;
 108                }
 109        }
 110}
 111
 112static int zynq_rproc_start(struct rproc *rproc)
 113{
 114        struct device *dev = rproc->dev.parent;
 115        int ret;
 116
 117        dev_dbg(dev, "%s\n", __func__);
 118        INIT_WORK(&workqueue, handle_event);
 119
 120        ret = cpu_down(1);
 121        /* EBUSY means CPU is already released */
 122        if (ret && (ret != -EBUSY)) {
 123                dev_err(dev, "Can't release cpu1\n");
 124                return ret;
 125        }
 126
 127        ret = zynq_cpun_start(rproc->bootaddr, 1);
 128        /* Trigger pending kicks */
 129        kick_pending_ipi(rproc);
 130
 131        return ret;
 132}
 133
 134/* kick a firmware */
 135static void zynq_rproc_kick(struct rproc *rproc, int vqid)
 136{
 137        struct device *dev = rproc->dev.parent;
 138        struct zynq_rproc_pdata *local = rproc->priv;
 139        struct rproc_vdev *rvdev, *rvtmp;
 140        int i;
 141
 142        dev_dbg(dev, "KICK Firmware to start send messages vqid %d\n", vqid);
 143
 144        list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node) {
 145                for (i = 0; i < MAX_NUM_VRINGS; i++) {
 146                        struct rproc_vring *rvring = &rvdev->vring[i];
 147
 148                        /* Send swirq to firmware */
 149                        if (rvring->notifyid == vqid) {
 150                                local->ipis[i].notifyid = vqid;
 151                                /* As we do not turn off CPU1 until start,
 152                                 * we delay firmware kick
 153                                 */
 154                                if (rproc->state == RPROC_RUNNING)
 155                                        gic_raise_softirq(cpumask_of(1),
 156                                                          local->ipis[i].irq);
 157                                else
 158                                        local->ipis[i].pending = true;
 159                        }
 160                }
 161        }
 162}
 163
 164/* power off the remote processor */
 165static int zynq_rproc_stop(struct rproc *rproc)
 166{
 167        int ret;
 168        struct device *dev = rproc->dev.parent;
 169
 170        dev_dbg(rproc->dev.parent, "%s\n", __func__);
 171
 172        /* Cpu can't be power on - for example in nosmp mode */
 173        ret = cpu_up(1);
 174        if (ret)
 175                dev_err(dev, "Can't power on cpu1 %d\n", ret);
 176
 177        return 0;
 178}
 179
 180static int zynq_parse_fw(struct rproc *rproc, const struct firmware *fw)
 181{
 182        int num_mems, i, ret;
 183        struct device *dev = rproc->dev.parent;
 184        struct device_node *np = dev->of_node;
 185        struct rproc_mem_entry *mem;
 186
 187        num_mems = of_count_phandle_with_args(np, "memory-region", NULL);
 188        if (num_mems <= 0)
 189                return 0;
 190        for (i = 0; i < num_mems; i++) {
 191                struct device_node *node;
 192                struct reserved_mem *rmem;
 193
 194                node = of_parse_phandle(np, "memory-region", i);
 195                rmem = of_reserved_mem_lookup(node);
 196                if (!rmem) {
 197                        dev_err(dev, "unable to acquire memory-region\n");
 198                        return -EINVAL;
 199                }
 200                if (strstr(node->name, "vdev") &&
 201                        strstr(node->name, "buffer")) {
 202                        /* Register DMA region */
 203                        mem = rproc_mem_entry_init(dev, NULL,
 204                                                   (dma_addr_t)rmem->base,
 205                                                   rmem->size, rmem->base,
 206                                                   NULL, NULL,
 207                                                   node->name);
 208                        if (!mem) {
 209                                dev_err(dev,
 210                                        "unable to initialize memory-region %s \n",
 211                                        node->name);
 212                                return -ENOMEM;
 213                        }
 214                        rproc_add_carveout(rproc, mem);
 215                } else if (strstr(node->name, "vdev") &&
 216                           strstr(node->name, "vring")) {
 217                        /* Register vring */
 218                        mem = rproc_mem_entry_init(dev, NULL,
 219                                                   (dma_addr_t)rmem->base,
 220                                                   rmem->size, rmem->base,
 221                                                   NULL, NULL,
 222                                                   node->name);
 223                        mem->va = devm_ioremap_wc(dev, rmem->base, rmem->size);
 224                        if (!mem->va)
 225                                return -ENOMEM;
 226                        if (!mem) {
 227                                dev_err(dev,
 228                                        "unable to initialize memory-region %s\n",
 229                                        node->name);
 230                                return -ENOMEM;
 231                        }
 232                        rproc_add_carveout(rproc, mem);
 233                } else {
 234                        mem = rproc_of_resm_mem_entry_init(dev, i,
 235                                                        rmem->size,
 236                                                        rmem->base,
 237                                                        node->name);
 238                        if (!mem) {
 239                                dev_err(dev,
 240                                        "unable to initialize memory-region %s \n",
 241                                        node->name);
 242                                return -ENOMEM;
 243                        }
 244                        mem->va = devm_ioremap_wc(dev, rmem->base, rmem->size);
 245                        if (!mem->va)
 246                                return -ENOMEM;
 247
 248                        rproc_add_carveout(rproc, mem);
 249                }
 250        }
 251
 252        ret = rproc_elf_load_rsc_table(rproc, fw);
 253        if (ret == -EINVAL)
 254                ret = 0;
 255        return ret;
 256}
 257
 258static struct rproc_ops zynq_rproc_ops = {
 259        .start          = zynq_rproc_start,
 260        .stop           = zynq_rproc_stop,
 261        .load           = rproc_elf_load_segments,
 262        .parse_fw       = zynq_parse_fw,
 263        .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
 264        .get_boot_addr  = rproc_elf_get_boot_addr,
 265        .kick           = zynq_rproc_kick,
 266};
 267
 268/* Just to detect bug if interrupt forwarding is broken */
 269static irqreturn_t zynq_remoteproc_interrupt(int irq, void *dev_id)
 270{
 271        struct device *dev = dev_id;
 272
 273        dev_err(dev, "GIC IRQ %d is not forwarded correctly\n", irq);
 274
 275        /*
 276         *  MS: Calling this function doesn't need to be BUG
 277         * especially for cases where firmware doesn't disable
 278         * interrupts. In next probing can be som interrupts pending.
 279         * The next scenario is for cases when you want to monitor
 280         * non frequent interrupt through Linux kernel. Interrupt happen
 281         * and it is forwarded to Linux which update own statistic
 282         * in (/proc/interrupt) and forward it to firmware.
 283         *
 284         * gic_set_cpu(1, irq); - setup cpu1 as destination cpu
 285         * gic_raise_softirq(cpumask_of(1), irq); - forward irq to firmware
 286         */
 287
 288        gic_set_cpu(1, irq);
 289        return IRQ_HANDLED;
 290}
 291
 292static void clear_irq(struct rproc *rproc)
 293{
 294        struct list_head *pos, *q;
 295        struct irq_list *tmp;
 296        struct zynq_rproc_pdata *local = rproc->priv;
 297
 298        dev_info(rproc->dev.parent, "Deleting the irq_list\n");
 299        list_for_each_safe(pos, q, &local->irqs.list) {
 300                tmp = list_entry(pos, struct irq_list, list);
 301                free_irq(tmp->irq, rproc->dev.parent);
 302                gic_set_cpu(0, tmp->irq);
 303                list_del(pos);
 304                kfree(tmp);
 305        }
 306}
 307
 308static int zynq_remoteproc_probe(struct platform_device *pdev)
 309{
 310        int ret = 0;
 311        struct irq_list *tmp;
 312        int count = 0;
 313        struct zynq_rproc_pdata *local;
 314
 315        rproc = rproc_alloc(&pdev->dev, dev_name(&pdev->dev),
 316                            &zynq_rproc_ops, NULL,
 317                sizeof(struct zynq_rproc_pdata));
 318        if (!rproc) {
 319                dev_err(&pdev->dev, "rproc allocation failed\n");
 320                ret = -ENOMEM;
 321                return ret;
 322        }
 323        local = rproc->priv;
 324        local->rproc = rproc;
 325
 326        platform_set_drvdata(pdev, rproc);
 327
 328        ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
 329        if (ret) {
 330                dev_err(&pdev->dev, "dma_set_coherent_mask: %d\n", ret);
 331                goto dma_mask_fault;
 332        }
 333
 334        /* Init list for IRQs - it can be long list */
 335        INIT_LIST_HEAD(&local->irqs.list);
 336
 337        /* Alloc IRQ based on DTS to be sure that no other driver will use it */
 338        while (1) {
 339                int irq;
 340
 341                irq = platform_get_irq(pdev, count++);
 342                if (irq == -ENXIO || irq == -EINVAL)
 343                        break;
 344
 345                tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
 346                if (!tmp) {
 347                        ret = -ENOMEM;
 348                        goto irq_fault;
 349                }
 350
 351                tmp->irq = irq;
 352
 353                dev_dbg(&pdev->dev, "%d: Alloc irq: %d\n", count, tmp->irq);
 354
 355                /* Allocating shared IRQs will ensure that any module will
 356                 * use these IRQs
 357                 */
 358                ret = request_irq(tmp->irq, zynq_remoteproc_interrupt, 0,
 359                                  dev_name(&pdev->dev), &pdev->dev);
 360                if (ret) {
 361                        dev_err(&pdev->dev, "IRQ %d already allocated\n",
 362                                tmp->irq);
 363                        goto irq_fault;
 364                }
 365
 366                /*
 367                 * MS: Here is place for detecting problem with firmware
 368                 * which doesn't work correctly with interrupts
 369                 *
 370                 * MS: Comment if you want to count IRQs on Linux
 371                 */
 372                gic_set_cpu(1, tmp->irq);
 373                list_add(&tmp->list, &local->irqs.list);
 374        }
 375
 376        /* Allocate free IPI number */
 377        /* Read vring0 ipi number */
 378        ret = of_property_read_u32(pdev->dev.of_node, "vring0",
 379                                   &local->ipis[0].irq);
 380        if (ret < 0) {
 381                dev_err(&pdev->dev, "unable to read property");
 382                goto irq_fault;
 383        }
 384
 385        ret = set_ipi_handler(local->ipis[0].irq, ipi_kick,
 386                              "Firmware kick");
 387        if (ret) {
 388                dev_err(&pdev->dev, "IPI handler already registered\n");
 389                goto irq_fault;
 390        }
 391
 392        /* Read vring1 ipi number */
 393        ret = of_property_read_u32(pdev->dev.of_node, "vring1",
 394                                   &local->ipis[1].irq);
 395        if (ret < 0) {
 396                dev_err(&pdev->dev, "unable to read property");
 397                goto ipi_fault;
 398        }
 399
 400        rproc->auto_boot = autoboot;
 401
 402        ret = rproc_add(local->rproc);
 403        if (ret) {
 404                dev_err(&pdev->dev, "rproc registration failed\n");
 405                goto ipi_fault;
 406        }
 407
 408        return 0;
 409
 410ipi_fault:
 411        clear_ipi_handler(local->ipis[0].irq);
 412
 413irq_fault:
 414        clear_irq(rproc);
 415
 416dma_mask_fault:
 417        rproc_free(rproc);
 418
 419        return ret;
 420}
 421
 422static int zynq_remoteproc_remove(struct platform_device *pdev)
 423{
 424        struct rproc *rproc = platform_get_drvdata(pdev);
 425        struct zynq_rproc_pdata *local = rproc->priv;
 426
 427        dev_info(&pdev->dev, "%s\n", __func__);
 428
 429        rproc_del(rproc);
 430
 431        clear_ipi_handler(local->ipis[0].irq);
 432        clear_irq(rproc);
 433
 434        of_reserved_mem_device_release(&pdev->dev);
 435        rproc_free(rproc);
 436
 437        return 0;
 438}
 439
 440/* Match table for OF platform binding */
 441static const struct of_device_id zynq_remoteproc_match[] = {
 442        { .compatible = "xlnx,zynq_remoteproc", },
 443        { /* end of list */ },
 444};
 445MODULE_DEVICE_TABLE(of, zynq_remoteproc_match);
 446
 447static struct platform_driver zynq_remoteproc_driver = {
 448        .probe = zynq_remoteproc_probe,
 449        .remove = zynq_remoteproc_remove,
 450        .driver = {
 451                .name = "zynq_remoteproc",
 452                .of_match_table = zynq_remoteproc_match,
 453        },
 454};
 455module_platform_driver(zynq_remoteproc_driver);
 456
 457module_param_named(autoboot,  autoboot, bool, 0444);
 458MODULE_PARM_DESC(autoboot,
 459                 "enable | disable autoboot. (default: false)");
 460
 461MODULE_AUTHOR("Michal Simek <monstr@monstr.eu");
 462MODULE_LICENSE("GPL v2");
 463MODULE_DESCRIPTION("Zynq remote processor control driver");
 464