uboot/drivers/remoteproc/rproc-uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2015
   4 * Texas Instruments Incorporated - http://www.ti.com/
   5 */
   6#define pr_fmt(fmt) "%s: " fmt, __func__
   7#include <common.h>
   8#include <errno.h>
   9#include <fdtdec.h>
  10#include <malloc.h>
  11#include <remoteproc.h>
  12#include <asm/io.h>
  13#include <dm/device-internal.h>
  14#include <dm.h>
  15#include <dm/uclass.h>
  16#include <dm/uclass-internal.h>
  17
  18DECLARE_GLOBAL_DATA_PTR;
  19
  20/**
  21 * for_each_remoteproc_device() - iterate through the list of rproc devices
  22 * @fn: check function to call per match, if this function returns fail,
  23 *      iteration is aborted with the resultant error value
  24 * @skip_dev:   Device to skip calling the callback about.
  25 * @data:       Data to pass to the callback function
  26 *
  27 * Return: 0 if none of the callback returned a non 0 result, else returns the
  28 * result from the callback function
  29 */
  30static int for_each_remoteproc_device(int (*fn) (struct udevice *dev,
  31                                        struct dm_rproc_uclass_pdata *uc_pdata,
  32                                        const void *data),
  33                                      struct udevice *skip_dev,
  34                                      const void *data)
  35{
  36        struct udevice *dev;
  37        struct dm_rproc_uclass_pdata *uc_pdata;
  38        int ret;
  39
  40        for (ret = uclass_find_first_device(UCLASS_REMOTEPROC, &dev); dev;
  41             ret = uclass_find_next_device(&dev)) {
  42                if (ret || dev == skip_dev)
  43                        continue;
  44                uc_pdata = dev_get_uclass_platdata(dev);
  45                ret = fn(dev, uc_pdata, data);
  46                if (ret)
  47                        return ret;
  48        }
  49
  50        return 0;
  51}
  52
  53/**
  54 * _rproc_name_is_unique() - iteration helper to check if rproc name is unique
  55 * @dev:        device that we are checking name for
  56 * @uc_pdata:   uclass platform data
  57 * @data:       compare data (this is the name we want to ensure is unique)
  58 *
  59 * Return: 0 is there is no match(is unique); if there is a match(we dont
  60 * have a unique name), return -EINVAL.
  61 */
  62static int _rproc_name_is_unique(struct udevice *dev,
  63                                 struct dm_rproc_uclass_pdata *uc_pdata,
  64                                 const void *data)
  65{
  66        const char *check_name = data;
  67
  68        /* devices not yet populated with data - so skip them */
  69        if (!uc_pdata->name || !check_name)
  70                return 0;
  71
  72        /* Return 0 to search further if we dont match */
  73        if (strlen(uc_pdata->name) != strlen(check_name))
  74                return 0;
  75
  76        if (!strcmp(uc_pdata->name, check_name))
  77                return -EINVAL;
  78
  79        return 0;
  80}
  81
  82/**
  83 * rproc_name_is_unique() - Check if the rproc name is unique
  84 * @check_dev:  Device we are attempting to ensure is unique
  85 * @check_name: Name we are trying to ensure is unique.
  86 *
  87 * Return: true if we have a unique name, false if name is not unique.
  88 */
  89static bool rproc_name_is_unique(struct udevice *check_dev,
  90                                 const char *check_name)
  91{
  92        int ret;
  93
  94        ret = for_each_remoteproc_device(_rproc_name_is_unique,
  95                                         check_dev, check_name);
  96        return ret ? false : true;
  97}
  98
  99/**
 100 * rproc_pre_probe() - Pre probe accessor for the uclass
 101 * @dev:        device for which we are preprobing
 102 *
 103 * Parses and fills up the uclass pdata for use as needed by core and
 104 * remote proc drivers.
 105 *
 106 * Return: 0 if all wernt ok, else appropriate error value.
 107 */
 108static int rproc_pre_probe(struct udevice *dev)
 109{
 110        struct dm_rproc_uclass_pdata *uc_pdata;
 111        const struct dm_rproc_ops *ops;
 112
 113        uc_pdata = dev_get_uclass_platdata(dev);
 114
 115        /* See if we need to populate via fdt */
 116
 117        if (!dev->platdata) {
 118#if CONFIG_IS_ENABLED(OF_CONTROL)
 119                int node = dev_of_offset(dev);
 120                const void *blob = gd->fdt_blob;
 121                bool tmp;
 122                if (!blob) {
 123                        debug("'%s' no dt?\n", dev->name);
 124                        return -EINVAL;
 125                }
 126                debug("'%s': using fdt\n", dev->name);
 127                uc_pdata->name = fdt_getprop(blob, node,
 128                                             "remoteproc-name", NULL);
 129
 130                /* Default is internal memory mapped */
 131                uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED;
 132                tmp = fdtdec_get_bool(blob, node,
 133                                      "remoteproc-internal-memory-mapped");
 134                if (tmp)
 135                        uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED;
 136#else
 137                /* Nothing much we can do about this, can we? */
 138                return -EINVAL;
 139#endif
 140
 141        } else {
 142                struct dm_rproc_uclass_pdata *pdata = dev->platdata;
 143
 144                debug("'%s': using legacy data\n", dev->name);
 145                if (pdata->name)
 146                        uc_pdata->name = pdata->name;
 147                uc_pdata->mem_type = pdata->mem_type;
 148                uc_pdata->driver_plat_data = pdata->driver_plat_data;
 149        }
 150
 151        /* Else try using device Name */
 152        if (!uc_pdata->name)
 153                uc_pdata->name = dev->name;
 154        if (!uc_pdata->name) {
 155                debug("Unnamed device!");
 156                return -EINVAL;
 157        }
 158
 159        if (!rproc_name_is_unique(dev, uc_pdata->name)) {
 160                debug("%s duplicate name '%s'\n", dev->name, uc_pdata->name);
 161                return -EINVAL;
 162        }
 163
 164        ops = rproc_get_ops(dev);
 165        if (!ops) {
 166                debug("%s driver has no ops?\n", dev->name);
 167                return -EINVAL;
 168        }
 169
 170        if (!ops->load || !ops->start) {
 171                debug("%s driver has missing mandatory ops?\n", dev->name);
 172                return -EINVAL;
 173        }
 174
 175        return 0;
 176}
 177
 178/**
 179 * rproc_post_probe() - post probe accessor for the uclass
 180 * @dev:        deivce we finished probing
 181 *
 182 * initiate init function after the probe is completed. This allows
 183 * the remote processor drivers to split up the initializations between
 184 * probe and init as needed.
 185 *
 186 * Return: if the remote proc driver has a init routine, invokes it and
 187 * hands over the return value. overall, 0 if all went well, else appropriate
 188 * error value.
 189 */
 190static int rproc_post_probe(struct udevice *dev)
 191{
 192        const struct dm_rproc_ops *ops;
 193
 194        ops = rproc_get_ops(dev);
 195        if (!ops) {
 196                debug("%s driver has no ops?\n", dev->name);
 197                return -EINVAL;
 198        }
 199
 200        if (ops->init)
 201                return ops->init(dev);
 202
 203        return 0;
 204}
 205
 206UCLASS_DRIVER(rproc) = {
 207        .id = UCLASS_REMOTEPROC,
 208        .name = "remoteproc",
 209        .flags = DM_UC_FLAG_SEQ_ALIAS,
 210        .pre_probe = rproc_pre_probe,
 211        .post_probe = rproc_post_probe,
 212        .per_device_platdata_auto_alloc_size =
 213                sizeof(struct dm_rproc_uclass_pdata),
 214};
 215
 216/* Remoteproc subsystem access functions */
 217/**
 218 * _rproc_probe_dev() - iteration helper to probe a rproc device
 219 * @dev:        device to probe
 220 * @uc_pdata:   uclass data allocated for the device
 221 * @data:       unused
 222 *
 223 * Return: 0 if all ok, else appropriate error value.
 224 */
 225static int _rproc_probe_dev(struct udevice *dev,
 226                            struct dm_rproc_uclass_pdata *uc_pdata,
 227                            const void *data)
 228{
 229        int ret;
 230
 231        ret = device_probe(dev);
 232
 233        if (ret)
 234                debug("%s: Failed to initialize - %d\n", dev->name, ret);
 235        return ret;
 236}
 237
 238/**
 239 * _rproc_dev_is_probed() - check if the device has been probed
 240 * @dev:        device to check
 241 * @uc_pdata:   unused
 242 * @data:       unused
 243 *
 244 * Return: -EAGAIN if not probed else return 0
 245 */
 246static int _rproc_dev_is_probed(struct udevice *dev,
 247                            struct dm_rproc_uclass_pdata *uc_pdata,
 248                            const void *data)
 249{
 250        if (dev->flags & DM_FLAG_ACTIVATED)
 251                return 0;
 252
 253        return -EAGAIN;
 254}
 255
 256bool rproc_is_initialized(void)
 257{
 258        int ret = for_each_remoteproc_device(_rproc_dev_is_probed, NULL, NULL);
 259        return ret ? false : true;
 260}
 261
 262int rproc_init(void)
 263{
 264        int ret;
 265
 266        if (rproc_is_initialized()) {
 267                debug("Already initialized\n");
 268                return -EINVAL;
 269        }
 270
 271        ret = for_each_remoteproc_device(_rproc_probe_dev, NULL, NULL);
 272        return ret;
 273}
 274
 275int rproc_dev_init(int id)
 276{
 277        struct udevice *dev = NULL;
 278        int ret;
 279
 280        ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
 281        if (ret) {
 282                debug("Unknown remote processor id '%d' requested(%d)\n",
 283                      id, ret);
 284                return ret;
 285        }
 286
 287        ret = device_probe(dev);
 288        if (ret)
 289                debug("%s: Failed to initialize - %d\n", dev->name, ret);
 290
 291        return ret;
 292}
 293
 294int rproc_load(int id, ulong addr, ulong size)
 295{
 296        struct udevice *dev = NULL;
 297        struct dm_rproc_uclass_pdata *uc_pdata;
 298        const struct dm_rproc_ops *ops;
 299        int ret;
 300
 301        ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
 302        if (ret) {
 303                debug("Unknown remote processor id '%d' requested(%d)\n",
 304                      id, ret);
 305                return ret;
 306        }
 307
 308        uc_pdata = dev_get_uclass_platdata(dev);
 309
 310        ops = rproc_get_ops(dev);
 311        if (!ops) {
 312                debug("%s driver has no ops?\n", dev->name);
 313                return -EINVAL;
 314        }
 315
 316        debug("Loading to '%s' from address 0x%08lX size of %lu bytes\n",
 317              uc_pdata->name, addr, size);
 318        if (ops->load)
 319                return ops->load(dev, addr, size);
 320
 321        debug("%s: data corruption?? mandatory function is missing!\n",
 322              dev->name);
 323
 324        return -EINVAL;
 325};
 326
 327/*
 328 * Completely internal helper enums..
 329 * Keeping this isolated helps this code evolve independent of other
 330 * parts..
 331 */
 332enum rproc_ops {
 333        RPROC_START,
 334        RPROC_STOP,
 335        RPROC_RESET,
 336        RPROC_PING,
 337        RPROC_RUNNING,
 338};
 339
 340/**
 341 * _rproc_ops_wrapper() - wrapper for invoking remote proc driver callback
 342 * @id:         id of the remote processor
 343 * @op:         one of rproc_ops that indicate what operation to invoke
 344 *
 345 * Most of the checks and verification for remoteproc operations are more
 346 * or less same for almost all operations. This allows us to put a wrapper
 347 * and use the common checks to allow the driver to function appropriately.
 348 *
 349 * Return: 0 if all ok, else appropriate error value.
 350 */
 351static int _rproc_ops_wrapper(int id, enum rproc_ops op)
 352{
 353        struct udevice *dev = NULL;
 354        struct dm_rproc_uclass_pdata *uc_pdata;
 355        const struct dm_rproc_ops *ops;
 356        int (*fn)(struct udevice *dev);
 357        bool mandatory = false;
 358        char *op_str;
 359        int ret;
 360
 361        ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev);
 362        if (ret) {
 363                debug("Unknown remote processor id '%d' requested(%d)\n",
 364                      id, ret);
 365                return ret;
 366        }
 367
 368        uc_pdata = dev_get_uclass_platdata(dev);
 369
 370        ops = rproc_get_ops(dev);
 371        if (!ops) {
 372                debug("%s driver has no ops?\n", dev->name);
 373                return -EINVAL;
 374        }
 375        switch (op) {
 376        case RPROC_START:
 377                fn = ops->start;
 378                mandatory = true;
 379                op_str = "Starting";
 380                break;
 381        case RPROC_STOP:
 382                fn = ops->stop;
 383                op_str = "Stopping";
 384                break;
 385        case RPROC_RESET:
 386                fn = ops->reset;
 387                op_str = "Resetting";
 388                break;
 389        case RPROC_RUNNING:
 390                fn = ops->is_running;
 391                op_str = "Checking if running:";
 392                break;
 393        case RPROC_PING:
 394                fn = ops->ping;
 395                op_str = "Pinging";
 396                break;
 397        default:
 398                debug("what is '%d' operation??\n", op);
 399                return -EINVAL;
 400        }
 401
 402        debug("%s %s...\n", op_str, uc_pdata->name);
 403        if (fn)
 404                return fn(dev);
 405
 406        if (mandatory)
 407                debug("%s: data corruption?? mandatory function is missing!\n",
 408                      dev->name);
 409
 410        return -ENOSYS;
 411}
 412
 413int rproc_start(int id)
 414{
 415        return _rproc_ops_wrapper(id, RPROC_START);
 416};
 417
 418int rproc_stop(int id)
 419{
 420        return _rproc_ops_wrapper(id, RPROC_STOP);
 421};
 422
 423int rproc_reset(int id)
 424{
 425        return _rproc_ops_wrapper(id, RPROC_RESET);
 426};
 427
 428int rproc_ping(int id)
 429{
 430        return _rproc_ops_wrapper(id, RPROC_PING);
 431};
 432
 433int rproc_is_running(int id)
 434{
 435        return _rproc_ops_wrapper(id, RPROC_RUNNING);
 436};
 437