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