linux/drivers/remoteproc/mb_remoteproc.c
<<
>>
Prefs
   1/*
   2 * Microblaze Remote Processor driver
   3 *
   4 * Copyright (C) 2012 - 2013 Michal Simek <monstr@monstr.eu>
   5 * Copyright (C) 2013 Xilinx, Inc.
   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 * This program is free software; you can redistribute it and/or
  14 * modify it under the terms of the GNU General Public License
  15 * version 2 as published by the Free Software Foundation.
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 * GNU General Public License for more details.
  21 */
  22
  23#include <linux/kernel.h>
  24#include <linux/module.h>
  25#include <linux/err.h>
  26#include <linux/platform_device.h>
  27#include <linux/dma-mapping.h>
  28#include <linux/remoteproc.h>
  29#include <linux/interrupt.h>
  30#include <linux/of_irq.h>
  31#include <linux/of_gpio.h>
  32#include <linux/of_platform.h>
  33#include <linux/smp.h>
  34#include <linux/irqchip/arm-gic.h>
  35#include <asm/outercache.h>
  36#include <asm/cacheflush.h>
  37#include <linux/slab.h>
  38#include <linux/cpu.h>
  39#include <linux/gpio.h>
  40#include <linux/io.h>
  41#include <linux/delay.h>
  42
  43#include "remoteproc_internal.h"
  44
  45/* Module parameter */
  46static char *firmware;
  47
  48/* Private data */
  49struct mb_rproc_pdata {
  50        struct rproc *rproc;
  51        u32 mem_start;
  52        u32 mem_end;
  53        int reset_gpio;
  54        int mb_debug_gpio;
  55        int ipi;
  56        int vring0;
  57        int vring1;
  58        void __iomem *vbase;
  59        const unsigned char *bootloader;
  60};
  61
  62/* Store rproc for IPI handler */
  63static struct platform_device *remoteprocdev;
  64static struct work_struct workqueue;
  65
  66static void handle_event(struct work_struct *work)
  67{
  68        struct mb_rproc_pdata *local = platform_get_drvdata(remoteprocdev);
  69
  70        flush_cache_all();
  71        outer_flush_range(local->mem_start, local->mem_end);
  72
  73        if (rproc_vq_interrupt(local->rproc, 0) == IRQ_NONE)
  74                dev_info(&remoteprocdev->dev, "no message found in vqid 0\n");
  75}
  76
  77static irqreturn_t ipi_kick(int irq, void *dev_id)
  78{
  79        dev_dbg(&remoteprocdev->dev, "KICK Linux because of pending message\n");
  80        schedule_work(&workqueue);
  81        dev_dbg(&remoteprocdev->dev, "KICK Linux handled\n");
  82
  83        return IRQ_HANDLED;
  84}
  85
  86static int mb_rproc_start(struct rproc *rproc)
  87{
  88        struct device *dev = rproc->dev.parent;
  89        struct platform_device *pdev = to_platform_device(dev);
  90        struct mb_rproc_pdata *local = platform_get_drvdata(pdev);
  91        const struct firmware *fw;
  92        int ret;
  93
  94        dev_info(dev, "%s\n", __func__);
  95        INIT_WORK(&workqueue, handle_event);
  96
  97        flush_cache_all();
  98        outer_flush_range(local->mem_start, local->mem_end);
  99
 100        remoteprocdev = pdev;
 101
 102        ret = request_firmware(&fw, local->bootloader, &pdev->dev);
 103        if (ret < 0) {
 104                dev_err(&pdev->dev, "request_firmware failed\n");
 105                return ret;
 106        }
 107        /* Copy bootloader to memory */
 108        memcpy(local->vbase, fw->data, fw->size);
 109        release_firmware(fw);
 110
 111        /* Just for sure synchronize memories */
 112        dsb();
 113
 114        /* Release Microblaze from reset */
 115        gpio_set_value(local->reset_gpio, 0);
 116
 117        return 0;
 118}
 119
 120/* kick a firmware */
 121static void mb_rproc_kick(struct rproc *rproc, int vqid)
 122{
 123        struct device *dev = rproc->dev.parent;
 124        struct platform_device *pdev = to_platform_device(dev);
 125        struct mb_rproc_pdata *local = platform_get_drvdata(pdev);
 126
 127        dev_dbg(dev, "KICK Firmware to start send messages vqid %d\n", vqid);
 128
 129        flush_cache_all();
 130        outer_flush_all();
 131
 132        /* Send swirq to firmware */
 133        gpio_set_value(local->vring0, 0);
 134        gpio_set_value(local->vring1, 0);
 135        dsb();
 136
 137        if (!vqid) {
 138                udelay(500);
 139                gpio_set_value(local->vring0, 1);
 140                dsb();
 141        } else {
 142                udelay(100);
 143                gpio_set_value(local->vring1, 1);
 144                dsb();
 145        }
 146}
 147
 148/* power off the remote processor */
 149static int mb_rproc_stop(struct rproc *rproc)
 150{
 151        struct device *dev = rproc->dev.parent;
 152        struct platform_device *pdev = to_platform_device(dev);
 153        struct mb_rproc_pdata *local = platform_get_drvdata(pdev);
 154
 155        /* Setup MB to the state where all memory transactions are done */
 156        gpio_set_value(local->mb_debug_gpio, 1);
 157        dsb(); /* Be sure that this write has been done */
 158        /*
 159         * This should be enough to ensure one CLK as
 160         * it is written in MB ref guide
 161         */
 162        gpio_set_value(local->mb_debug_gpio, 0);
 163
 164        udelay(1000); /* Wait some time to finish all mem transactions */
 165
 166        /* Add Microblaze to reset state */
 167        gpio_set_value(local->reset_gpio, 1);
 168
 169        /* No reason to wait that operations where done */
 170        return 0;
 171}
 172
 173static struct rproc_ops mb_rproc_ops = {
 174        .start          = mb_rproc_start,
 175        .stop           = mb_rproc_stop,
 176        .kick           = mb_rproc_kick,
 177};
 178
 179/* Just to detect bug if interrupt forwarding is broken */
 180static irqreturn_t mb_remoteproc_interrupt(int irq, void *dev_id)
 181{
 182        struct device *dev = dev_id;
 183
 184        dev_err(dev, "GIC IRQ %d is not forwarded correctly\n", irq);
 185
 186        return IRQ_HANDLED;
 187}
 188
 189static int mb_remoteproc_probe(struct platform_device *pdev)
 190{
 191        const unsigned char *prop;
 192        struct platform_device *bram_pdev;
 193        struct device_node *bram_dev;
 194        struct resource *res; /* IO mem resources */
 195        int ret = 0;
 196        int count = 0;
 197        struct mb_rproc_pdata *local;
 198
 199        local = devm_kzalloc(&pdev->dev, sizeof(*local), GFP_KERNEL);
 200        if (!local)
 201                return -ENOMEM;
 202
 203        platform_set_drvdata(pdev, local);
 204
 205        /* Declare memory for firmware */
 206        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 207        if (!res) {
 208                dev_err(&pdev->dev, "invalid address\n");
 209                return -ENODEV;
 210        }
 211
 212        local->mem_start = res->start;
 213        local->mem_end = res->end;
 214
 215        /* Alloc phys addr from 0 to max_addr for firmware */
 216        ret = dma_declare_coherent_memory(&pdev->dev, local->mem_start,
 217                local->mem_start, local->mem_end - local->mem_start + 1,
 218                DMA_MEMORY_IO);
 219        if (!ret) {
 220                dev_err(&pdev->dev, "dma_declare_coherent_memory failed\n");
 221                return -ENOMEM;
 222        }
 223
 224        ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
 225        if (ret) {
 226                dev_err(&pdev->dev, "dma_set_coherent_mask: %d\n", ret);
 227                goto dma_mask_fault;
 228        }
 229
 230        /* Alloc IRQ based on DTS to be sure that no other driver will use it */
 231        while (1) {
 232                int irq;
 233                /* Allocating shared IRQs will ensure that any module will
 234                 * use these IRQs */
 235                irq = platform_get_irq(pdev, count++);
 236                if (irq == -ENXIO || irq == -EINVAL)
 237                        break;
 238                ret = devm_request_irq(&pdev->dev, irq, mb_remoteproc_interrupt,
 239                                       0, dev_name(&pdev->dev), &pdev->dev);
 240                if (ret) {
 241                        dev_err(&pdev->dev, "IRQ %d already allocated\n", irq);
 242                        goto dma_mask_fault;
 243                }
 244
 245                dev_info(&pdev->dev, "%d: Alloc irq: %d\n", count, irq);
 246        }
 247
 248        /* Find out reset gpio and keep microblaze in reset */
 249        local->reset_gpio = of_get_named_gpio(pdev->dev.of_node, "reset", 0);
 250        if (local->reset_gpio < 0) {
 251                dev_err(&pdev->dev, "reset-gpio property not found\n");
 252                ret = local->reset_gpio;
 253                goto dma_mask_fault;
 254        }
 255        ret = devm_gpio_request_one(&pdev->dev, local->reset_gpio,
 256                                    GPIOF_OUT_INIT_HIGH, "mb_reset");
 257        if (ret) {
 258                dev_err(&pdev->dev, "Please specify gpio reset addr\n");
 259                goto dma_mask_fault;
 260        }
 261
 262        /* Find out reset gpio and keep microblaze in reset */
 263        local->mb_debug_gpio = of_get_named_gpio(pdev->dev.of_node, "debug", 0);
 264        if (local->mb_debug_gpio < 0) {
 265                dev_err(&pdev->dev, "mb-debug-gpio property not found\n");
 266                ret = local->mb_debug_gpio;
 267                goto dma_mask_fault;
 268        }
 269        ret = devm_gpio_request_one(&pdev->dev, local->mb_debug_gpio,
 270                                    GPIOF_OUT_INIT_LOW, "mb_debug");
 271        if (ret) {
 272                dev_err(&pdev->dev, "Please specify gpio debug pin\n");
 273                goto dma_mask_fault;
 274        }
 275
 276        /* IPI number for getting irq from firmware */
 277        local->ipi = of_get_named_gpio(pdev->dev.of_node, "ipino", 0);
 278        if (local->ipi < 0) {
 279                dev_err(&pdev->dev, "ipi-gpio property not found\n");
 280                ret = local->ipi;
 281                goto dma_mask_fault;
 282        }
 283        ret = devm_gpio_request_one(&pdev->dev, local->ipi, GPIOF_IN, "mb_ipi");
 284        if (ret) {
 285                dev_err(&pdev->dev, "Please specify gpio reset addr\n");
 286                goto dma_mask_fault;
 287        }
 288        ret = devm_request_irq(&pdev->dev, gpio_to_irq(local->ipi),
 289                               ipi_kick, IRQF_SHARED|IRQF_TRIGGER_RISING,
 290                               dev_name(&pdev->dev), local);
 291        if (ret) {
 292                dev_err(&pdev->dev, "IRQ %d already allocated\n", local->ipi);
 293                goto dma_mask_fault;
 294        }
 295
 296        /* Find out vring0 pin */
 297        local->vring0 = of_get_named_gpio(pdev->dev.of_node, "vring0", 0);
 298        if (local->vring0 < 0) {
 299                dev_err(&pdev->dev, "reset-gpio property not found\n");
 300                ret = local->vring0;
 301                goto dma_mask_fault;
 302        }
 303        ret = devm_gpio_request_one(&pdev->dev, local->vring0,
 304                                    GPIOF_DIR_OUT, "mb_vring0");
 305        if (ret) {
 306                dev_err(&pdev->dev, "Please specify gpio reset addr\n");
 307                goto dma_mask_fault;
 308        }
 309
 310        /* Find out vring1 pin */
 311        local->vring1 = of_get_named_gpio(pdev->dev.of_node, "vring1", 0);
 312        if (local->vring1 < 0) {
 313                dev_err(&pdev->dev, "reset-gpio property not found\n");
 314                ret = local->vring1;
 315                goto dma_mask_fault;
 316        }
 317        ret = devm_gpio_request_one(&pdev->dev, local->vring1,
 318                                    GPIOF_DIR_OUT, "mb_vring1");
 319        if (ret) {
 320                dev_err(&pdev->dev, "Please specify gpio reset addr\n");
 321                goto dma_mask_fault;
 322        }
 323
 324        /* Allocate bram device */
 325        bram_dev = of_parse_phandle(pdev->dev.of_node, "bram", 0);
 326        if (!bram_dev) {
 327                dev_err(&pdev->dev, "Please specify bram connection\n");
 328                ret = -ENODEV;
 329                goto dma_mask_fault;
 330        }
 331        bram_pdev = of_find_device_by_node(bram_dev);
 332        if (!bram_pdev) {
 333                dev_err(&pdev->dev, "BRAM device hasn't found\n");
 334                ret = -ENODEV;
 335                goto dma_mask_fault;
 336        }
 337        res = platform_get_resource(bram_pdev, IORESOURCE_MEM, 0);
 338        local->vbase = devm_ioremap_resource(&pdev->dev, res);
 339        if (!local->vbase) {
 340                ret = -ENODEV;
 341                goto dma_mask_fault;
 342        }
 343
 344        /* Load simple bootloader to bram */
 345        local->bootloader = of_get_property(pdev->dev.of_node,
 346                                            "bram-firmware", NULL);
 347        if (!local->bootloader) {
 348                dev_err(&pdev->dev, "Please specify BRAM firmware\n");
 349                ret = -ENODEV;
 350                goto dma_mask_fault;
 351        }
 352
 353        dev_info(&pdev->dev, "Using microblaze BRAM bootloader: %s\n",
 354                 local->bootloader);
 355
 356        /* Module param firmware first */
 357        if (firmware)
 358                prop = firmware;
 359        else
 360                prop = of_get_property(pdev->dev.of_node, "firmware", NULL);
 361
 362        if (prop) {
 363                dev_info(&pdev->dev, "Using firmware: %s\n", prop);
 364                local->rproc = rproc_alloc(&pdev->dev, dev_name(&pdev->dev),
 365                                &mb_rproc_ops, prop, sizeof(struct rproc));
 366                if (!local->rproc) {
 367                        dev_err(&pdev->dev, "rproc allocation failed\n");
 368                        ret = -ENODEV;
 369                        goto dma_mask_fault;
 370                }
 371
 372                ret = rproc_add(local->rproc);
 373                if (ret) {
 374                        dev_err(&pdev->dev, "rproc registration failed\n");
 375                        rproc_put(local->rproc);
 376                        goto dma_mask_fault;
 377                }
 378                return 0;
 379        }
 380
 381        ret = -ENODEV;
 382
 383dma_mask_fault:
 384        dma_release_declared_memory(&pdev->dev);
 385
 386        return ret;
 387}
 388
 389static int mb_remoteproc_remove(struct platform_device *pdev)
 390{
 391        struct mb_rproc_pdata *local = platform_get_drvdata(pdev);
 392
 393        dev_info(&pdev->dev, "%s\n", __func__);
 394
 395        dma_release_declared_memory(&pdev->dev);
 396
 397        rproc_del(local->rproc);
 398        rproc_put(local->rproc);
 399
 400        return 0;
 401}
 402
 403/* Match table for OF platform binding */
 404static struct of_device_id mb_remoteproc_match[] = {
 405        { .compatible = "xlnx,mb_remoteproc", },
 406        { /* end of list */ },
 407};
 408MODULE_DEVICE_TABLE(of, mb_remoteproc_match);
 409
 410static struct platform_driver mb_remoteproc_driver = {
 411        .probe = mb_remoteproc_probe,
 412        .remove = mb_remoteproc_remove,
 413        .driver = {
 414                .name = "mb_remoteproc",
 415                .of_match_table = mb_remoteproc_match,
 416        },
 417};
 418module_platform_driver(mb_remoteproc_driver);
 419
 420module_param(firmware, charp, 0);
 421MODULE_PARM_DESC(firmware, "Override the firmware image name. Default value in DTS.");
 422
 423MODULE_AUTHOR("Michal Simek <monstr@monstr.eu");
 424MODULE_LICENSE("GPL v2");
 425MODULE_DESCRIPTION("Microblaze remote processor control driver");
 426