root/drivers/dma/of-dma.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. of_dma_find_controller
  2. of_dma_router_xlate
  3. of_dma_controller_register
  4. of_dma_controller_free
  5. of_dma_router_register
  6. of_dma_match_channel
  7. of_dma_request_slave_channel
  8. of_dma_simple_xlate
  9. of_dma_xlate_by_chan_id

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

/* [<][>][^][v][top][bottom][index][help] */