linux/drivers/dma/of-dma.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Device tree helpers for DMA request / controller
   4 *
   5 * Based on of_gpio.c
   6 *
   7 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
   8 */
   9
  10#include <linux/device.h>
  11#include <linux/err.h>
  12#include <linux/module.h>
  13#include <linux/mutex.h>
  14#include <linux/slab.h>
  15#include <linux/of.h>
  16#include <linux/of_dma.h>
  17
  18#include "dmaengine.h"
  19
  20static LIST_HEAD(of_dma_list);
  21static DEFINE_MUTEX(of_dma_lock);
  22
  23/**
  24 * of_dma_find_controller - Get a DMA controller in DT DMA helpers list
  25 * @dma_spec:   pointer to DMA specifier as found in the device tree
  26 *
  27 * Finds a DMA controller with matching device node and number for dma cells
  28 * in a list of registered DMA controllers. If a match is found a valid pointer
  29 * to the DMA data stored is retuned. A NULL pointer is returned if no match is
  30 * found.
  31 */
  32static struct of_dma *of_dma_find_controller(struct of_phandle_args *dma_spec)
  33{
  34        struct of_dma *ofdma;
  35
  36        list_for_each_entry(ofdma, &of_dma_list, of_dma_controllers)
  37                if (ofdma->of_node == dma_spec->np)
  38                        return ofdma;
  39
  40        pr_debug("%s: can't find DMA controller %pOF\n", __func__,
  41                 dma_spec->np);
  42
  43        return NULL;
  44}
  45
  46/**
  47 * of_dma_router_xlate - translation function for router devices
  48 * @dma_spec:   pointer to DMA specifier as found in the device tree
  49 * @ofdma:      pointer to DMA controller data (router information)
  50 *
  51 * The function creates new dma_spec to be passed to the router driver's
  52 * of_dma_route_allocate() function to prepare a dma_spec which will be used
  53 * to request channel from the real DMA controller.
  54 */
  55static struct dma_chan *of_dma_router_xlate(struct of_phandle_args *dma_spec,
  56                                            struct of_dma *ofdma)
  57{
  58        struct dma_chan         *chan;
  59        struct of_dma           *ofdma_target;
  60        struct of_phandle_args  dma_spec_target;
  61        void                    *route_data;
  62
  63        /* translate the request for the real DMA controller */
  64        memcpy(&dma_spec_target, dma_spec, sizeof(dma_spec_target));
  65        route_data = ofdma->of_dma_route_allocate(&dma_spec_target, ofdma);
  66        if (IS_ERR(route_data))
  67                return NULL;
  68
  69        ofdma_target = of_dma_find_controller(&dma_spec_target);
  70        if (!ofdma_target) {
  71                ofdma->dma_router->route_free(ofdma->dma_router->dev,
  72                                              route_data);
  73                chan = ERR_PTR(-EPROBE_DEFER);
  74                goto err;
  75        }
  76
  77        chan = ofdma_target->of_dma_xlate(&dma_spec_target, ofdma_target);
  78        if (IS_ERR_OR_NULL(chan)) {
  79                ofdma->dma_router->route_free(ofdma->dma_router->dev,
  80                                              route_data);
  81        } else {
  82                int ret = 0;
  83
  84                chan->router = ofdma->dma_router;
  85                chan->route_data = route_data;
  86
  87                if (chan->device->device_router_config)
  88                        ret = chan->device->device_router_config(chan);
  89
  90                if (ret) {
  91                        dma_release_channel(chan);
  92                        chan = ERR_PTR(ret);
  93                }
  94        }
  95
  96err:
  97        /*
  98         * Need to put the node back since the ofdma->of_dma_route_allocate
  99         * has taken it for generating the new, translated dma_spec
 100         */
 101        of_node_put(dma_spec_target.np);
 102        return chan;
 103}
 104
 105/**
 106 * of_dma_controller_register - Register a DMA controller to DT DMA helpers
 107 * @np:                 device node of DMA controller
 108 * @of_dma_xlate:       translation function which converts a phandle
 109 *                      arguments list into a dma_chan structure
 110 * @data:               pointer to controller specific data to be used by
 111 *                      translation function
 112 *
 113 * Returns 0 on success or appropriate errno value on error.
 114 *
 115 * Allocated memory should be freed with appropriate of_dma_controller_free()
 116 * call.
 117 */
 118int of_dma_controller_register(struct device_node *np,
 119                                struct dma_chan *(*of_dma_xlate)
 120                                (struct of_phandle_args *, struct of_dma *),
 121                                void *data)
 122{
 123        struct of_dma   *ofdma;
 124
 125        if (!np || !of_dma_xlate) {
 126                pr_err("%s: not enough information provided\n", __func__);
 127                return -EINVAL;
 128        }
 129
 130        ofdma = kzalloc(sizeof(*ofdma), GFP_KERNEL);
 131        if (!ofdma)
 132                return -ENOMEM;
 133
 134        ofdma->of_node = np;
 135        ofdma->of_dma_xlate = of_dma_xlate;
 136        ofdma->of_dma_data = data;
 137
 138        /* Now queue of_dma controller structure in list */
 139        mutex_lock(&of_dma_lock);
 140        list_add_tail(&ofdma->of_dma_controllers, &of_dma_list);
 141        mutex_unlock(&of_dma_lock);
 142
 143        return 0;
 144}
 145EXPORT_SYMBOL_GPL(of_dma_controller_register);
 146
 147/**
 148 * of_dma_controller_free - Remove a DMA controller from DT DMA helpers list
 149 * @np:         device node of DMA controller
 150 *
 151 * Memory allocated by of_dma_controller_register() is freed here.
 152 */
 153void of_dma_controller_free(struct device_node *np)
 154{
 155        struct of_dma *ofdma;
 156
 157        mutex_lock(&of_dma_lock);
 158
 159        list_for_each_entry(ofdma, &of_dma_list, of_dma_controllers)
 160                if (ofdma->of_node == np) {
 161                        list_del(&ofdma->of_dma_controllers);
 162                        kfree(ofdma);
 163                        break;
 164                }
 165
 166        mutex_unlock(&of_dma_lock);
 167}
 168EXPORT_SYMBOL_GPL(of_dma_controller_free);
 169
 170/**
 171 * of_dma_router_register - Register a DMA router to DT DMA helpers as a
 172 *                          controller
 173 * @np:                         device node of DMA router
 174 * @of_dma_route_allocate:      setup function for the router which need to
 175 *                              modify the dma_spec for the DMA controller to
 176 *                              use and to set up the requested route.
 177 * @dma_router:                 pointer to dma_router structure to be used when
 178 *                              the route need to be free up.
 179 *
 180 * Returns 0 on success or appropriate errno value on error.
 181 *
 182 * Allocated memory should be freed with appropriate of_dma_controller_free()
 183 * call.
 184 */
 185int of_dma_router_register(struct device_node *np,
 186                           void *(*of_dma_route_allocate)
 187                           (struct of_phandle_args *, struct of_dma *),
 188                           struct dma_router *dma_router)
 189{
 190        struct of_dma   *ofdma;
 191
 192        if (!np || !of_dma_route_allocate || !dma_router) {
 193                pr_err("%s: not enough information provided\n", __func__);
 194                return -EINVAL;
 195        }
 196
 197        ofdma = kzalloc(sizeof(*ofdma), GFP_KERNEL);
 198        if (!ofdma)
 199                return -ENOMEM;
 200
 201        ofdma->of_node = np;
 202        ofdma->of_dma_xlate = of_dma_router_xlate;
 203        ofdma->of_dma_route_allocate = of_dma_route_allocate;
 204        ofdma->dma_router = dma_router;
 205
 206        /* Now queue of_dma controller structure in list */
 207        mutex_lock(&of_dma_lock);
 208        list_add_tail(&ofdma->of_dma_controllers, &of_dma_list);
 209        mutex_unlock(&of_dma_lock);
 210
 211        return 0;
 212}
 213EXPORT_SYMBOL_GPL(of_dma_router_register);
 214
 215/**
 216 * of_dma_match_channel - Check if a DMA specifier matches name
 217 * @np:         device node to look for DMA channels
 218 * @name:       channel name to be matched
 219 * @index:      index of DMA specifier in list of DMA specifiers
 220 * @dma_spec:   pointer to DMA specifier as found in the device tree
 221 *
 222 * Check if the DMA specifier pointed to by the index in a list of DMA
 223 * specifiers, matches the name provided. Returns 0 if the name matches and
 224 * a valid pointer to the DMA specifier is found. Otherwise returns -ENODEV.
 225 */
 226static int of_dma_match_channel(struct device_node *np, const char *name,
 227                                int index, struct of_phandle_args *dma_spec)
 228{
 229        const char *s;
 230
 231        if (of_property_read_string_index(np, "dma-names", index, &s))
 232                return -ENODEV;
 233
 234        if (strcmp(name, s))
 235                return -ENODEV;
 236
 237        if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index,
 238                                       dma_spec))
 239                return -ENODEV;
 240
 241        return 0;
 242}
 243
 244/**
 245 * of_dma_request_slave_channel - Get the DMA slave channel
 246 * @np:         device node to get DMA request from
 247 * @name:       name of desired channel
 248 *
 249 * Returns pointer to appropriate DMA channel on success or an error pointer.
 250 */
 251struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
 252                                              const char *name)
 253{
 254        struct of_phandle_args  dma_spec;
 255        struct of_dma           *ofdma;
 256        struct dma_chan         *chan;
 257        int                     count, i, start;
 258        int                     ret_no_channel = -ENODEV;
 259        static atomic_t         last_index;
 260
 261        if (!np || !name) {
 262                pr_err("%s: not enough information provided\n", __func__);
 263                return ERR_PTR(-ENODEV);
 264        }
 265
 266        /* Silently fail if there is not even the "dmas" property */
 267        if (!of_find_property(np, "dmas", NULL))
 268                return ERR_PTR(-ENODEV);
 269
 270        count = of_property_count_strings(np, "dma-names");
 271        if (count < 0) {
 272                pr_err("%s: dma-names property of node '%pOF' missing or empty\n",
 273                        __func__, np);
 274                return ERR_PTR(-ENODEV);
 275        }
 276
 277        /*
 278         * approximate an average distribution across multiple
 279         * entries with the same name
 280         */
 281        start = atomic_inc_return(&last_index);
 282        for (i = 0; i < count; i++) {
 283                if (of_dma_match_channel(np, name,
 284                                         (i + start) % count,
 285                                         &dma_spec))
 286                        continue;
 287
 288                mutex_lock(&of_dma_lock);
 289                ofdma = of_dma_find_controller(&dma_spec);
 290
 291                if (ofdma) {
 292                        chan = ofdma->of_dma_xlate(&dma_spec, ofdma);
 293                } else {
 294                        ret_no_channel = -EPROBE_DEFER;
 295                        chan = NULL;
 296                }
 297
 298                mutex_unlock(&of_dma_lock);
 299
 300                of_node_put(dma_spec.np);
 301
 302                if (chan)
 303                        return chan;
 304        }
 305
 306        return ERR_PTR(ret_no_channel);
 307}
 308EXPORT_SYMBOL_GPL(of_dma_request_slave_channel);
 309
 310/**
 311 * of_dma_simple_xlate - Simple DMA engine translation function
 312 * @dma_spec:   pointer to DMA specifier as found in the device tree
 313 * @ofdma:      pointer to DMA controller data
 314 *
 315 * A simple translation function for devices that use a 32-bit value for the
 316 * filter_param when calling the DMA engine dma_request_channel() function.
 317 * Note that this translation function requires that #dma-cells is equal to 1
 318 * and the argument of the dma specifier is the 32-bit filter_param. Returns
 319 * pointer to appropriate dma channel on success or NULL on error.
 320 */
 321struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
 322                                                struct of_dma *ofdma)
 323{
 324        int count = dma_spec->args_count;
 325        struct of_dma_filter_info *info = ofdma->of_dma_data;
 326
 327        if (!info || !info->filter_fn)
 328                return NULL;
 329
 330        if (count != 1)
 331                return NULL;
 332
 333        return __dma_request_channel(&info->dma_cap, info->filter_fn,
 334                                     &dma_spec->args[0], dma_spec->np);
 335}
 336EXPORT_SYMBOL_GPL(of_dma_simple_xlate);
 337
 338/**
 339 * of_dma_xlate_by_chan_id - Translate dt property to DMA channel by channel id
 340 * @dma_spec:   pointer to DMA specifier as found in the device tree
 341 * @ofdma:      pointer to DMA controller data
 342 *
 343 * This function can be used as the of xlate callback for DMA driver which wants
 344 * to match the channel based on the channel id. When using this xlate function
 345 * the #dma-cells propety of the DMA controller dt node needs to be set to 1.
 346 * The data parameter of of_dma_controller_register must be a pointer to the
 347 * dma_device struct the function should match upon.
 348 *
 349 * Returns pointer to appropriate dma channel on success or NULL on error.
 350 */
 351struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
 352                                         struct of_dma *ofdma)
 353{
 354        struct dma_device *dev = ofdma->of_dma_data;
 355        struct dma_chan *chan, *candidate = NULL;
 356
 357        if (!dev || dma_spec->args_count != 1)
 358                return NULL;
 359
 360        list_for_each_entry(chan, &dev->channels, device_node)
 361                if (chan->chan_id == dma_spec->args[0]) {
 362                        candidate = chan;
 363                        break;
 364                }
 365
 366        if (!candidate)
 367                return NULL;
 368
 369        return dma_get_slave_channel(candidate);
 370}
 371EXPORT_SYMBOL_GPL(of_dma_xlate_by_chan_id);
 372