linux/drivers/remoteproc/keystone_remoteproc.c
<<
>>
Prefs
   1/*
   2 * TI Keystone DSP remoteproc driver
   3 *
   4 * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * version 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License for more details.
  14 */
  15
  16#include <linux/module.h>
  17#include <linux/slab.h>
  18#include <linux/io.h>
  19#include <linux/interrupt.h>
  20#include <linux/platform_device.h>
  21#include <linux/pm_runtime.h>
  22#include <linux/workqueue.h>
  23#include <linux/of_address.h>
  24#include <linux/of_reserved_mem.h>
  25#include <linux/of_gpio.h>
  26#include <linux/regmap.h>
  27#include <linux/mfd/syscon.h>
  28#include <linux/remoteproc.h>
  29#include <linux/reset.h>
  30
  31#include "remoteproc_internal.h"
  32
  33#define KEYSTONE_RPROC_LOCAL_ADDRESS_MASK       (SZ_16M - 1)
  34
  35/**
  36 * struct keystone_rproc_mem - internal memory structure
  37 * @cpu_addr: MPU virtual address of the memory region
  38 * @bus_addr: Bus address used to access the memory region
  39 * @dev_addr: Device address of the memory region from DSP view
  40 * @size: Size of the memory region
  41 */
  42struct keystone_rproc_mem {
  43        void __iomem *cpu_addr;
  44        phys_addr_t bus_addr;
  45        u32 dev_addr;
  46        size_t size;
  47};
  48
  49/**
  50 * struct keystone_rproc - keystone remote processor driver structure
  51 * @dev: cached device pointer
  52 * @rproc: remoteproc device handle
  53 * @mem: internal memory regions data
  54 * @num_mems: number of internal memory regions
  55 * @dev_ctrl: device control regmap handle
  56 * @reset: reset control handle
  57 * @boot_offset: boot register offset in @dev_ctrl regmap
  58 * @irq_ring: irq entry for vring
  59 * @irq_fault: irq entry for exception
  60 * @kick_gpio: gpio used for virtio kicks
  61 * @workqueue: workqueue for processing virtio interrupts
  62 */
  63struct keystone_rproc {
  64        struct device *dev;
  65        struct rproc *rproc;
  66        struct keystone_rproc_mem *mem;
  67        int num_mems;
  68        struct regmap *dev_ctrl;
  69        struct reset_control *reset;
  70        u32 boot_offset;
  71        int irq_ring;
  72        int irq_fault;
  73        int kick_gpio;
  74        struct work_struct workqueue;
  75};
  76
  77/* Put the DSP processor into reset */
  78static void keystone_rproc_dsp_reset(struct keystone_rproc *ksproc)
  79{
  80        reset_control_assert(ksproc->reset);
  81}
  82
  83/* Configure the boot address and boot the DSP processor */
  84static int keystone_rproc_dsp_boot(struct keystone_rproc *ksproc, u32 boot_addr)
  85{
  86        int ret;
  87
  88        if (boot_addr & (SZ_1K - 1)) {
  89                dev_err(ksproc->dev, "invalid boot address 0x%x, must be aligned on a 1KB boundary\n",
  90                        boot_addr);
  91                return -EINVAL;
  92        }
  93
  94        ret = regmap_write(ksproc->dev_ctrl, ksproc->boot_offset, boot_addr);
  95        if (ret) {
  96                dev_err(ksproc->dev, "regmap_write of boot address failed, status = %d\n",
  97                        ret);
  98                return ret;
  99        }
 100
 101        reset_control_deassert(ksproc->reset);
 102
 103        return 0;
 104}
 105
 106/*
 107 * Process the remoteproc exceptions
 108 *
 109 * The exception reporting on Keystone DSP remote processors is very simple
 110 * compared to the equivalent processors on the OMAP family, it is notified
 111 * through a software-designed specific interrupt source in the IPC interrupt
 112 * generation register.
 113 *
 114 * This function just invokes the rproc_report_crash to report the exception
 115 * to the remoteproc driver core, to trigger a recovery.
 116 */
 117static irqreturn_t keystone_rproc_exception_interrupt(int irq, void *dev_id)
 118{
 119        struct keystone_rproc *ksproc = dev_id;
 120
 121        rproc_report_crash(ksproc->rproc, RPROC_FATAL_ERROR);
 122
 123        return IRQ_HANDLED;
 124}
 125
 126/*
 127 * Main virtqueue message workqueue function
 128 *
 129 * This function is executed upon scheduling of the keystone remoteproc
 130 * driver's workqueue. The workqueue is scheduled by the vring ISR handler.
 131 *
 132 * There is no payload message indicating the virtqueue index as is the
 133 * case with mailbox-based implementations on OMAP family. As such, this
 134 * handler processes both the Tx and Rx virtqueue indices on every invocation.
 135 * The rproc_vq_interrupt function can detect if there are new unprocessed
 136 * messages or not (returns IRQ_NONE vs IRQ_HANDLED), but there is no need
 137 * to check for these return values. The index 0 triggering will process all
 138 * pending Rx buffers, and the index 1 triggering will process all newly
 139 * available Tx buffers and will wakeup any potentially blocked senders.
 140 *
 141 * NOTE:
 142 * 1. A payload could be added by using some of the source bits in the
 143 *    IPC interrupt generation registers, but this would need additional
 144 *    changes to the overall IPC stack, and currently there are no benefits
 145 *    of adapting that approach.
 146 * 2. The current logic is based on an inherent design assumption of supporting
 147 *    only 2 vrings, but this can be changed if needed.
 148 */
 149static void handle_event(struct work_struct *work)
 150{
 151        struct keystone_rproc *ksproc =
 152                container_of(work, struct keystone_rproc, workqueue);
 153
 154        rproc_vq_interrupt(ksproc->rproc, 0);
 155        rproc_vq_interrupt(ksproc->rproc, 1);
 156}
 157
 158/*
 159 * Interrupt handler for processing vring kicks from remote processor
 160 */
 161static irqreturn_t keystone_rproc_vring_interrupt(int irq, void *dev_id)
 162{
 163        struct keystone_rproc *ksproc = dev_id;
 164
 165        schedule_work(&ksproc->workqueue);
 166
 167        return IRQ_HANDLED;
 168}
 169
 170/*
 171 * Power up the DSP remote processor.
 172 *
 173 * This function will be invoked only after the firmware for this rproc
 174 * was loaded, parsed successfully, and all of its resource requirements
 175 * were met.
 176 */
 177static int keystone_rproc_start(struct rproc *rproc)
 178{
 179        struct keystone_rproc *ksproc = rproc->priv;
 180        int ret;
 181
 182        INIT_WORK(&ksproc->workqueue, handle_event);
 183
 184        ret = request_irq(ksproc->irq_ring, keystone_rproc_vring_interrupt, 0,
 185                          dev_name(ksproc->dev), ksproc);
 186        if (ret) {
 187                dev_err(ksproc->dev, "failed to enable vring interrupt, ret = %d\n",
 188                        ret);
 189                goto out;
 190        }
 191
 192        ret = request_irq(ksproc->irq_fault, keystone_rproc_exception_interrupt,
 193                          0, dev_name(ksproc->dev), ksproc);
 194        if (ret) {
 195                dev_err(ksproc->dev, "failed to enable exception interrupt, ret = %d\n",
 196                        ret);
 197                goto free_vring_irq;
 198        }
 199
 200        ret = keystone_rproc_dsp_boot(ksproc, rproc->bootaddr);
 201        if (ret)
 202                goto free_exc_irq;
 203
 204        return 0;
 205
 206free_exc_irq:
 207        free_irq(ksproc->irq_fault, ksproc);
 208free_vring_irq:
 209        free_irq(ksproc->irq_ring, ksproc);
 210        flush_work(&ksproc->workqueue);
 211out:
 212        return ret;
 213}
 214
 215/*
 216 * Stop the DSP remote processor.
 217 *
 218 * This function puts the DSP processor into reset, and finishes processing
 219 * of any pending messages.
 220 */
 221static int keystone_rproc_stop(struct rproc *rproc)
 222{
 223        struct keystone_rproc *ksproc = rproc->priv;
 224
 225        keystone_rproc_dsp_reset(ksproc);
 226        free_irq(ksproc->irq_fault, ksproc);
 227        free_irq(ksproc->irq_ring, ksproc);
 228        flush_work(&ksproc->workqueue);
 229
 230        return 0;
 231}
 232
 233/*
 234 * Kick the remote processor to notify about pending unprocessed messages.
 235 * The vqid usage is not used and is inconsequential, as the kick is performed
 236 * through a simulated GPIO (a bit in an IPC interrupt-triggering register),
 237 * the remote processor is expected to process both its Tx and Rx virtqueues.
 238 */
 239static void keystone_rproc_kick(struct rproc *rproc, int vqid)
 240{
 241        struct keystone_rproc *ksproc = rproc->priv;
 242
 243        if (WARN_ON(ksproc->kick_gpio < 0))
 244                return;
 245
 246        gpio_set_value(ksproc->kick_gpio, 1);
 247}
 248
 249/*
 250 * Custom function to translate a DSP device address (internal RAMs only) to a
 251 * kernel virtual address.  The DSPs can access their RAMs at either an internal
 252 * address visible only from a DSP, or at the SoC-level bus address. Both these
 253 * addresses need to be looked through for translation. The translated addresses
 254 * can be used either by the remoteproc core for loading (when using kernel
 255 * remoteproc loader), or by any rpmsg bus drivers.
 256 */
 257static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
 258{
 259        struct keystone_rproc *ksproc = rproc->priv;
 260        void __iomem *va = NULL;
 261        phys_addr_t bus_addr;
 262        u32 dev_addr, offset;
 263        size_t size;
 264        int i;
 265
 266        if (len <= 0)
 267                return NULL;
 268
 269        for (i = 0; i < ksproc->num_mems; i++) {
 270                bus_addr = ksproc->mem[i].bus_addr;
 271                dev_addr = ksproc->mem[i].dev_addr;
 272                size = ksproc->mem[i].size;
 273
 274                if (da < KEYSTONE_RPROC_LOCAL_ADDRESS_MASK) {
 275                        /* handle DSP-view addresses */
 276                        if ((da >= dev_addr) &&
 277                            ((da + len) <= (dev_addr + size))) {
 278                                offset = da - dev_addr;
 279                                va = ksproc->mem[i].cpu_addr + offset;
 280                                break;
 281                        }
 282                } else {
 283                        /* handle SoC-view addresses */
 284                        if ((da >= bus_addr) &&
 285                            (da + len) <= (bus_addr + size)) {
 286                                offset = da - bus_addr;
 287                                va = ksproc->mem[i].cpu_addr + offset;
 288                                break;
 289                        }
 290                }
 291        }
 292
 293        return (__force void *)va;
 294}
 295
 296static const struct rproc_ops keystone_rproc_ops = {
 297        .start          = keystone_rproc_start,
 298        .stop           = keystone_rproc_stop,
 299        .kick           = keystone_rproc_kick,
 300        .da_to_va       = keystone_rproc_da_to_va,
 301};
 302
 303static int keystone_rproc_of_get_memories(struct platform_device *pdev,
 304                                          struct keystone_rproc *ksproc)
 305{
 306        static const char * const mem_names[] = {"l2sram", "l1pram", "l1dram"};
 307        struct device *dev = &pdev->dev;
 308        struct resource *res;
 309        int num_mems = 0;
 310        int i;
 311
 312        num_mems = ARRAY_SIZE(mem_names);
 313        ksproc->mem = devm_kcalloc(ksproc->dev, num_mems,
 314                                   sizeof(*ksproc->mem), GFP_KERNEL);
 315        if (!ksproc->mem)
 316                return -ENOMEM;
 317
 318        for (i = 0; i < num_mems; i++) {
 319                res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 320                                                   mem_names[i]);
 321                ksproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res);
 322                if (IS_ERR(ksproc->mem[i].cpu_addr)) {
 323                        dev_err(dev, "failed to parse and map %s memory\n",
 324                                mem_names[i]);
 325                        return PTR_ERR(ksproc->mem[i].cpu_addr);
 326                }
 327                ksproc->mem[i].bus_addr = res->start;
 328                ksproc->mem[i].dev_addr =
 329                                res->start & KEYSTONE_RPROC_LOCAL_ADDRESS_MASK;
 330                ksproc->mem[i].size = resource_size(res);
 331
 332                /* zero out memories to start in a pristine state */
 333                memset((__force void *)ksproc->mem[i].cpu_addr, 0,
 334                       ksproc->mem[i].size);
 335        }
 336        ksproc->num_mems = num_mems;
 337
 338        return 0;
 339}
 340
 341static int keystone_rproc_of_get_dev_syscon(struct platform_device *pdev,
 342                                            struct keystone_rproc *ksproc)
 343{
 344        struct device_node *np = pdev->dev.of_node;
 345        struct device *dev = &pdev->dev;
 346        int ret;
 347
 348        if (!of_property_read_bool(np, "ti,syscon-dev")) {
 349                dev_err(dev, "ti,syscon-dev property is absent\n");
 350                return -EINVAL;
 351        }
 352
 353        ksproc->dev_ctrl =
 354                syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev");
 355        if (IS_ERR(ksproc->dev_ctrl)) {
 356                ret = PTR_ERR(ksproc->dev_ctrl);
 357                return ret;
 358        }
 359
 360        if (of_property_read_u32_index(np, "ti,syscon-dev", 1,
 361                                       &ksproc->boot_offset)) {
 362                dev_err(dev, "couldn't read the boot register offset\n");
 363                return -EINVAL;
 364        }
 365
 366        return 0;
 367}
 368
 369static int keystone_rproc_probe(struct platform_device *pdev)
 370{
 371        struct device *dev = &pdev->dev;
 372        struct device_node *np = dev->of_node;
 373        struct keystone_rproc *ksproc;
 374        struct rproc *rproc;
 375        int dsp_id;
 376        char *fw_name = NULL;
 377        char *template = "keystone-dsp%d-fw";
 378        int name_len = 0;
 379        int ret = 0;
 380
 381        if (!np) {
 382                dev_err(dev, "only DT-based devices are supported\n");
 383                return -ENODEV;
 384        }
 385
 386        dsp_id = of_alias_get_id(np, "rproc");
 387        if (dsp_id < 0) {
 388                dev_warn(dev, "device does not have an alias id\n");
 389                return dsp_id;
 390        }
 391
 392        /* construct a custom default fw name - subject to change in future */
 393        name_len = strlen(template); /* assuming a single digit alias */
 394        fw_name = devm_kzalloc(dev, name_len, GFP_KERNEL);
 395        if (!fw_name)
 396                return -ENOMEM;
 397        snprintf(fw_name, name_len, template, dsp_id);
 398
 399        rproc = rproc_alloc(dev, dev_name(dev), &keystone_rproc_ops, fw_name,
 400                            sizeof(*ksproc));
 401        if (!rproc)
 402                return -ENOMEM;
 403
 404        rproc->has_iommu = false;
 405        ksproc = rproc->priv;
 406        ksproc->rproc = rproc;
 407        ksproc->dev = dev;
 408
 409        ret = keystone_rproc_of_get_dev_syscon(pdev, ksproc);
 410        if (ret)
 411                goto free_rproc;
 412
 413        ksproc->reset = devm_reset_control_get_exclusive(dev, NULL);
 414        if (IS_ERR(ksproc->reset)) {
 415                ret = PTR_ERR(ksproc->reset);
 416                goto free_rproc;
 417        }
 418
 419        /* enable clock for accessing DSP internal memories */
 420        pm_runtime_enable(dev);
 421        ret = pm_runtime_get_sync(dev);
 422        if (ret < 0) {
 423                dev_err(dev, "failed to enable clock, status = %d\n", ret);
 424                pm_runtime_put_noidle(dev);
 425                goto disable_rpm;
 426        }
 427
 428        ret = keystone_rproc_of_get_memories(pdev, ksproc);
 429        if (ret)
 430                goto disable_clk;
 431
 432        ksproc->irq_ring = platform_get_irq_byname(pdev, "vring");
 433        if (ksproc->irq_ring < 0) {
 434                ret = ksproc->irq_ring;
 435                dev_err(dev, "failed to get vring interrupt, status = %d\n",
 436                        ret);
 437                goto disable_clk;
 438        }
 439
 440        ksproc->irq_fault = platform_get_irq_byname(pdev, "exception");
 441        if (ksproc->irq_fault < 0) {
 442                ret = ksproc->irq_fault;
 443                dev_err(dev, "failed to get exception interrupt, status = %d\n",
 444                        ret);
 445                goto disable_clk;
 446        }
 447
 448        ksproc->kick_gpio = of_get_named_gpio_flags(np, "kick-gpios", 0, NULL);
 449        if (ksproc->kick_gpio < 0) {
 450                ret = ksproc->kick_gpio;
 451                dev_err(dev, "failed to get gpio for virtio kicks, status = %d\n",
 452                        ret);
 453                goto disable_clk;
 454        }
 455
 456        if (of_reserved_mem_device_init(dev))
 457                dev_warn(dev, "device does not have specific CMA pool\n");
 458
 459        /* ensure the DSP is in reset before loading firmware */
 460        ret = reset_control_status(ksproc->reset);
 461        if (ret < 0) {
 462                dev_err(dev, "failed to get reset status, status = %d\n", ret);
 463                goto release_mem;
 464        } else if (ret == 0) {
 465                WARN(1, "device is not in reset\n");
 466                keystone_rproc_dsp_reset(ksproc);
 467        }
 468
 469        ret = rproc_add(rproc);
 470        if (ret) {
 471                dev_err(dev, "failed to add register device with remoteproc core, status = %d\n",
 472                        ret);
 473                goto release_mem;
 474        }
 475
 476        platform_set_drvdata(pdev, ksproc);
 477
 478        return 0;
 479
 480release_mem:
 481        of_reserved_mem_device_release(dev);
 482disable_clk:
 483        pm_runtime_put_sync(dev);
 484disable_rpm:
 485        pm_runtime_disable(dev);
 486free_rproc:
 487        rproc_free(rproc);
 488        return ret;
 489}
 490
 491static int keystone_rproc_remove(struct platform_device *pdev)
 492{
 493        struct keystone_rproc *ksproc = platform_get_drvdata(pdev);
 494
 495        rproc_del(ksproc->rproc);
 496        pm_runtime_put_sync(&pdev->dev);
 497        pm_runtime_disable(&pdev->dev);
 498        rproc_free(ksproc->rproc);
 499        of_reserved_mem_device_release(&pdev->dev);
 500
 501        return 0;
 502}
 503
 504static const struct of_device_id keystone_rproc_of_match[] = {
 505        { .compatible = "ti,k2hk-dsp", },
 506        { .compatible = "ti,k2l-dsp", },
 507        { .compatible = "ti,k2e-dsp", },
 508        { .compatible = "ti,k2g-dsp", },
 509        { /* sentinel */ },
 510};
 511MODULE_DEVICE_TABLE(of, keystone_rproc_of_match);
 512
 513static struct platform_driver keystone_rproc_driver = {
 514        .probe  = keystone_rproc_probe,
 515        .remove = keystone_rproc_remove,
 516        .driver = {
 517                .name = "keystone-rproc",
 518                .of_match_table = keystone_rproc_of_match,
 519        },
 520};
 521
 522module_platform_driver(keystone_rproc_driver);
 523
 524MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
 525MODULE_LICENSE("GPL v2");
 526MODULE_DESCRIPTION("TI Keystone DSP Remoteproc driver");
 527