linux/drivers/remoteproc/st_remoteproc.c
<<
>>
Prefs
   1/*
   2 * ST's Remote Processor Control Driver
   3 *
   4 * Copyright (C) 2015 STMicroelectronics - All Rights Reserved
   5 *
   6 * Author: Ludovic Barre <ludovic.barre@st.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/clk.h>
  14#include <linux/dma-mapping.h>
  15#include <linux/err.h>
  16#include <linux/interrupt.h>
  17#include <linux/kernel.h>
  18#include <linux/mailbox_client.h>
  19#include <linux/mfd/syscon.h>
  20#include <linux/module.h>
  21#include <linux/of.h>
  22#include <linux/of_device.h>
  23#include <linux/of_reserved_mem.h>
  24#include <linux/platform_device.h>
  25#include <linux/regmap.h>
  26#include <linux/remoteproc.h>
  27#include <linux/reset.h>
  28
  29#include "remoteproc_internal.h"
  30
  31#define ST_RPROC_VQ0            0
  32#define ST_RPROC_VQ1            1
  33#define ST_RPROC_MAX_VRING      2
  34
  35#define MBOX_RX                 0
  36#define MBOX_TX                 1
  37#define MBOX_MAX                2
  38
  39struct st_rproc_config {
  40        bool                    sw_reset;
  41        bool                    pwr_reset;
  42        unsigned long           bootaddr_mask;
  43};
  44
  45struct st_rproc {
  46        struct st_rproc_config  *config;
  47        struct reset_control    *sw_reset;
  48        struct reset_control    *pwr_reset;
  49        struct clk              *clk;
  50        u32                     clk_rate;
  51        struct regmap           *boot_base;
  52        u32                     boot_offset;
  53        struct mbox_chan        *mbox_chan[ST_RPROC_MAX_VRING * MBOX_MAX];
  54        struct mbox_client mbox_client_vq0;
  55        struct mbox_client mbox_client_vq1;
  56};
  57
  58static void st_rproc_mbox_callback(struct device *dev, u32 msg)
  59{
  60        struct rproc *rproc = dev_get_drvdata(dev);
  61
  62        if (rproc_vq_interrupt(rproc, msg) == IRQ_NONE)
  63                dev_dbg(dev, "no message was found in vqid %d\n", msg);
  64}
  65
  66static
  67void st_rproc_mbox_callback_vq0(struct mbox_client *mbox_client, void *data)
  68{
  69        st_rproc_mbox_callback(mbox_client->dev, 0);
  70}
  71
  72static
  73void st_rproc_mbox_callback_vq1(struct mbox_client *mbox_client, void *data)
  74{
  75        st_rproc_mbox_callback(mbox_client->dev, 1);
  76}
  77
  78static void st_rproc_kick(struct rproc *rproc, int vqid)
  79{
  80        struct st_rproc *ddata = rproc->priv;
  81        struct device *dev = rproc->dev.parent;
  82        int ret;
  83
  84        /* send the index of the triggered virtqueue in the mailbox payload */
  85        if (WARN_ON(vqid >= ST_RPROC_MAX_VRING))
  86                return;
  87
  88        ret = mbox_send_message(ddata->mbox_chan[vqid * MBOX_MAX + MBOX_TX],
  89                                (void *)&vqid);
  90        if (ret < 0)
  91                dev_err(dev, "failed to send message via mbox: %d\n", ret);
  92}
  93
  94static int st_rproc_start(struct rproc *rproc)
  95{
  96        struct st_rproc *ddata = rproc->priv;
  97        int err;
  98
  99        regmap_update_bits(ddata->boot_base, ddata->boot_offset,
 100                           ddata->config->bootaddr_mask, rproc->bootaddr);
 101
 102        err = clk_enable(ddata->clk);
 103        if (err) {
 104                dev_err(&rproc->dev, "Failed to enable clock\n");
 105                return err;
 106        }
 107
 108        if (ddata->config->sw_reset) {
 109                err = reset_control_deassert(ddata->sw_reset);
 110                if (err) {
 111                        dev_err(&rproc->dev, "Failed to deassert S/W Reset\n");
 112                        goto sw_reset_fail;
 113                }
 114        }
 115
 116        if (ddata->config->pwr_reset) {
 117                err = reset_control_deassert(ddata->pwr_reset);
 118                if (err) {
 119                        dev_err(&rproc->dev, "Failed to deassert Power Reset\n");
 120                        goto pwr_reset_fail;
 121                }
 122        }
 123
 124        dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
 125
 126        return 0;
 127
 128
 129pwr_reset_fail:
 130        if (ddata->config->pwr_reset)
 131                reset_control_assert(ddata->sw_reset);
 132sw_reset_fail:
 133        clk_disable(ddata->clk);
 134
 135        return err;
 136}
 137
 138static int st_rproc_stop(struct rproc *rproc)
 139{
 140        struct st_rproc *ddata = rproc->priv;
 141        int sw_err = 0, pwr_err = 0;
 142
 143        if (ddata->config->sw_reset) {
 144                sw_err = reset_control_assert(ddata->sw_reset);
 145                if (sw_err)
 146                        dev_err(&rproc->dev, "Failed to assert S/W Reset\n");
 147        }
 148
 149        if (ddata->config->pwr_reset) {
 150                pwr_err = reset_control_assert(ddata->pwr_reset);
 151                if (pwr_err)
 152                        dev_err(&rproc->dev, "Failed to assert Power Reset\n");
 153        }
 154
 155        clk_disable(ddata->clk);
 156
 157        return sw_err ?: pwr_err;
 158}
 159
 160static const struct rproc_ops st_rproc_ops = {
 161        .kick           = st_rproc_kick,
 162        .start          = st_rproc_start,
 163        .stop           = st_rproc_stop,
 164};
 165
 166/*
 167 * Fetch state of the processor: 0 is off, 1 is on.
 168 */
 169static int st_rproc_state(struct platform_device *pdev)
 170{
 171        struct rproc *rproc = platform_get_drvdata(pdev);
 172        struct st_rproc *ddata = rproc->priv;
 173        int reset_sw = 0, reset_pwr = 0;
 174
 175        if (ddata->config->sw_reset)
 176                reset_sw = reset_control_status(ddata->sw_reset);
 177
 178        if (ddata->config->pwr_reset)
 179                reset_pwr = reset_control_status(ddata->pwr_reset);
 180
 181        if (reset_sw < 0 || reset_pwr < 0)
 182                return -EINVAL;
 183
 184        return !reset_sw && !reset_pwr;
 185}
 186
 187static const struct st_rproc_config st40_rproc_cfg = {
 188        .sw_reset = true,
 189        .pwr_reset = true,
 190        .bootaddr_mask = GENMASK(28, 1),
 191};
 192
 193static const struct st_rproc_config st231_rproc_cfg = {
 194        .sw_reset = true,
 195        .pwr_reset = false,
 196        .bootaddr_mask = GENMASK(31, 6),
 197};
 198
 199static const struct of_device_id st_rproc_match[] = {
 200        { .compatible = "st,st40-rproc", .data = &st40_rproc_cfg },
 201        { .compatible = "st,st231-rproc", .data = &st231_rproc_cfg },
 202        {},
 203};
 204MODULE_DEVICE_TABLE(of, st_rproc_match);
 205
 206static int st_rproc_parse_dt(struct platform_device *pdev)
 207{
 208        struct device *dev = &pdev->dev;
 209        struct rproc *rproc = platform_get_drvdata(pdev);
 210        struct st_rproc *ddata = rproc->priv;
 211        struct device_node *np = dev->of_node;
 212        int err;
 213
 214        if (ddata->config->sw_reset) {
 215                ddata->sw_reset = devm_reset_control_get_exclusive(dev,
 216                                                                   "sw_reset");
 217                if (IS_ERR(ddata->sw_reset)) {
 218                        dev_err(dev, "Failed to get S/W Reset\n");
 219                        return PTR_ERR(ddata->sw_reset);
 220                }
 221        }
 222
 223        if (ddata->config->pwr_reset) {
 224                ddata->pwr_reset = devm_reset_control_get_exclusive(dev,
 225                                                                    "pwr_reset");
 226                if (IS_ERR(ddata->pwr_reset)) {
 227                        dev_err(dev, "Failed to get Power Reset\n");
 228                        return PTR_ERR(ddata->pwr_reset);
 229                }
 230        }
 231
 232        ddata->clk = devm_clk_get(dev, NULL);
 233        if (IS_ERR(ddata->clk)) {
 234                dev_err(dev, "Failed to get clock\n");
 235                return PTR_ERR(ddata->clk);
 236        }
 237
 238        err = of_property_read_u32(np, "clock-frequency", &ddata->clk_rate);
 239        if (err) {
 240                dev_err(dev, "failed to get clock frequency\n");
 241                return err;
 242        }
 243
 244        ddata->boot_base = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
 245        if (IS_ERR(ddata->boot_base)) {
 246                dev_err(dev, "Boot base not found\n");
 247                return PTR_ERR(ddata->boot_base);
 248        }
 249
 250        err = of_property_read_u32_index(np, "st,syscfg", 1,
 251                                         &ddata->boot_offset);
 252        if (err) {
 253                dev_err(dev, "Boot offset not found\n");
 254                return -EINVAL;
 255        }
 256
 257        err = of_reserved_mem_device_init(dev);
 258        if (err) {
 259                dev_err(dev, "Failed to obtain shared memory\n");
 260                return err;
 261        }
 262
 263        err = clk_prepare(ddata->clk);
 264        if (err)
 265                dev_err(dev, "failed to get clock\n");
 266
 267        return err;
 268}
 269
 270static int st_rproc_probe(struct platform_device *pdev)
 271{
 272        struct device *dev = &pdev->dev;
 273        const struct of_device_id *match;
 274        struct st_rproc *ddata;
 275        struct device_node *np = dev->of_node;
 276        struct rproc *rproc;
 277        struct mbox_chan *chan;
 278        int enabled;
 279        int ret, i;
 280
 281        match = of_match_device(st_rproc_match, dev);
 282        if (!match || !match->data) {
 283                dev_err(dev, "No device match found\n");
 284                return -ENODEV;
 285        }
 286
 287        rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
 288        if (!rproc)
 289                return -ENOMEM;
 290
 291        rproc->has_iommu = false;
 292        ddata = rproc->priv;
 293        ddata->config = (struct st_rproc_config *)match->data;
 294
 295        platform_set_drvdata(pdev, rproc);
 296
 297        ret = st_rproc_parse_dt(pdev);
 298        if (ret)
 299                goto free_rproc;
 300
 301        enabled = st_rproc_state(pdev);
 302        if (enabled < 0) {
 303                ret = enabled;
 304                goto free_clk;
 305        }
 306
 307        if (enabled) {
 308                atomic_inc(&rproc->power);
 309                rproc->state = RPROC_RUNNING;
 310        } else {
 311                clk_set_rate(ddata->clk, ddata->clk_rate);
 312        }
 313
 314        if (of_get_property(np, "mbox-names", NULL)) {
 315                ddata->mbox_client_vq0.dev              = dev;
 316                ddata->mbox_client_vq0.tx_done          = NULL;
 317                ddata->mbox_client_vq0.tx_block = false;
 318                ddata->mbox_client_vq0.knows_txdone     = false;
 319                ddata->mbox_client_vq0.rx_callback      = st_rproc_mbox_callback_vq0;
 320
 321                ddata->mbox_client_vq1.dev              = dev;
 322                ddata->mbox_client_vq1.tx_done          = NULL;
 323                ddata->mbox_client_vq1.tx_block = false;
 324                ddata->mbox_client_vq1.knows_txdone     = false;
 325                ddata->mbox_client_vq1.rx_callback      = st_rproc_mbox_callback_vq1;
 326
 327                /*
 328                 * To control a co-processor without IPC mechanism.
 329                 * This driver can be used without mbox and rpmsg.
 330                 */
 331                chan = mbox_request_channel_byname(&ddata->mbox_client_vq0, "vq0_rx");
 332                if (IS_ERR(chan)) {
 333                        dev_err(&rproc->dev, "failed to request mbox chan 0\n");
 334                        ret = PTR_ERR(chan);
 335                        goto free_clk;
 336                }
 337                ddata->mbox_chan[ST_RPROC_VQ0 * MBOX_MAX + MBOX_RX] = chan;
 338
 339                chan = mbox_request_channel_byname(&ddata->mbox_client_vq0, "vq0_tx");
 340                if (IS_ERR(chan)) {
 341                        dev_err(&rproc->dev, "failed to request mbox chan 0\n");
 342                        ret = PTR_ERR(chan);
 343                        goto free_mbox;
 344                }
 345                ddata->mbox_chan[ST_RPROC_VQ0 * MBOX_MAX + MBOX_TX] = chan;
 346
 347                chan = mbox_request_channel_byname(&ddata->mbox_client_vq1, "vq1_rx");
 348                if (IS_ERR(chan)) {
 349                        dev_err(&rproc->dev, "failed to request mbox chan 1\n");
 350                        ret = PTR_ERR(chan);
 351                        goto free_mbox;
 352                }
 353                ddata->mbox_chan[ST_RPROC_VQ1 * MBOX_MAX + MBOX_RX] = chan;
 354
 355                chan = mbox_request_channel_byname(&ddata->mbox_client_vq1, "vq1_tx");
 356                if (IS_ERR(chan)) {
 357                        dev_err(&rproc->dev, "failed to request mbox chan 1\n");
 358                        ret = PTR_ERR(chan);
 359                        goto free_mbox;
 360                }
 361                ddata->mbox_chan[ST_RPROC_VQ1 * MBOX_MAX + MBOX_TX] = chan;
 362        }
 363
 364        ret = rproc_add(rproc);
 365        if (ret)
 366                goto free_mbox;
 367
 368        return 0;
 369
 370free_mbox:
 371        for (i = 0; i < ST_RPROC_MAX_VRING * MBOX_MAX; i++)
 372                mbox_free_channel(ddata->mbox_chan[i]);
 373free_clk:
 374        clk_unprepare(ddata->clk);
 375free_rproc:
 376        rproc_free(rproc);
 377        return ret;
 378}
 379
 380static int st_rproc_remove(struct platform_device *pdev)
 381{
 382        struct rproc *rproc = platform_get_drvdata(pdev);
 383        struct st_rproc *ddata = rproc->priv;
 384        int i;
 385
 386        rproc_del(rproc);
 387
 388        clk_disable_unprepare(ddata->clk);
 389
 390        of_reserved_mem_device_release(&pdev->dev);
 391
 392        for (i = 0; i < ST_RPROC_MAX_VRING * MBOX_MAX; i++)
 393                mbox_free_channel(ddata->mbox_chan[i]);
 394
 395        rproc_free(rproc);
 396
 397        return 0;
 398}
 399
 400static struct platform_driver st_rproc_driver = {
 401        .probe = st_rproc_probe,
 402        .remove = st_rproc_remove,
 403        .driver = {
 404                .name = "st-rproc",
 405                .of_match_table = of_match_ptr(st_rproc_match),
 406        },
 407};
 408module_platform_driver(st_rproc_driver);
 409
 410MODULE_DESCRIPTION("ST Remote Processor Control Driver");
 411MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
 412MODULE_LICENSE("GPL v2");
 413