Re: [U-Boot] [PATCH v5 02/15] dma: add channels support

2018-03-11 Thread Daniel Schwierzeck
Hi Álvaro,

sorry for the late response.

On 05.03.2018 21:05, Álvaro Fernández Rojas wrote:
> This adds channels support for dma controllers that have multiple channels
> which can transfer data to/from different devices (enet, usb...).
> 
> Signed-off-by: Álvaro Fernández Rojas 
> Reviewed-by: Simon Glass 
> ---
>  v5: remove unneeded dma.h include
>  v4: no changes
>  v3: Introduce changes reported by Simon Glass:
>   - Improve dma-uclass.h documentation.
>   - Switch to live tree API.
> 
>  drivers/dma/Kconfig  |   7 ++
>  drivers/dma/dma-uclass.c | 188 
> +--
>  include/dma-uclass.h |  78 
>  include/dma.h| 174 ++-
>  4 files changed, 439 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
> index 1b92c7789d..21b2c0dcaa 100644
> --- a/drivers/dma/Kconfig
> +++ b/drivers/dma/Kconfig
> @@ -12,6 +12,13 @@ config DMA
> buses that is used to transfer data to and from memory.
> The uclass interface is defined in include/dma.h.
>  
> +config DMA_CHANNELS
> + bool "Enable DMA channels support"
> + depends on DMA
> + help
> +   Enable channels support for DMA. Some DMA controllers have multiple
> +   channels which can either transfer data to/from different devices.
> +
>  config TI_EDMA3
>   bool "TI EDMA3 driver"
>   help
> diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
> index faa27a3a56..b5109aafc9 100644
> --- a/drivers/dma/dma-uclass.c
> +++ b/drivers/dma/dma-uclass.c
> @@ -1,23 +1,199 @@
>  /*
>   * Direct Memory Access U-Class driver
>   *
> - * (C) Copyright 2015
> - * Texas Instruments Incorporated, 
> - *
> - * Author: Mugunthan V N 
> + * Copyright (C) 2018 Álvaro Fernández Rojas 
> + * Copyright (C) 2015 Texas Instruments Incorporated 
> + * Written by Mugunthan V N 
>   *
>   * SPDX-License-Identifier: GPL-2.0+
>   */
>  
>  #include 
>  #include 
> -#include 
> -#include 
> +#include 
>  #include 
> +#include 
>  #include 
>  
>  DECLARE_GLOBAL_DATA_PTR;
>  
> +#ifdef CONFIG_DMA_CHANNELS
> +static inline struct dma_ops *dma_dev_ops(struct udevice *dev)
> +{
> + return (struct dma_ops *)dev->driver->ops;
> +}
> +
> +# if CONFIG_IS_ENABLED(OF_CONTROL)
> +#  if CONFIG_IS_ENABLED(OF_PLATDATA)
> +int dma_get_by_index_platdata(struct udevice *dev, int index,
> +   struct phandle_1_arg *cells, struct dma *dma)
> +{
> + int ret;
> +
> + if (index != 0)
> + return -ENOSYS;
> + ret = uclass_get_device(UCLASS_DMA, 0, >dev);
> + if (ret)
> + return ret;
> + dma->id = cells[0].id;
> +
> + return 0;
> +}
> +#  else
> +static int dma_of_xlate_default(struct dma *dma,
> + struct ofnode_phandle_args *args)
> +{
> + debug("%s(dma=%p)\n", __func__, dma);
> +
> + if (args->args_count > 1) {
> + pr_err("Invaild args_count: %d\n", args->args_count);
> + return -EINVAL;
> + }
> +
> + if (args->args_count)
> + dma->id = args->args[0];
> + else
> + dma->id = 0;
> +
> + return 0;
> +}
> +
> +int dma_get_by_index(struct udevice *dev, int index, struct dma *dma)
> +{
> + int ret;
> + struct ofnode_phandle_args args;
> + struct udevice *dev_dma;
> + const struct dma_ops *ops;
> +
> + debug("%s(dev=%p, index=%d, dma=%p)\n", __func__, dev, index, dma);
> +
> + assert(dma);
> + dma->dev = NULL;
> +
> + ret = dev_read_phandle_with_args(dev, "dmas", "#dma-cells", 0, index,
> +  );
> + if (ret) {
> + pr_err("%s: dev_read_phandle_with_args failed: err=%d\n",
> +__func__, ret);
> + return ret;
> + }
> +
> + ret = uclass_get_device_by_ofnode(UCLASS_DMA, args.node, _dma);
> + if (ret) {
> + pr_err("%s: uclass_get_device_by_ofnode failed: err=%d\n",
> +__func__, ret);
> + return ret;
> + }
> +
> + dma->dev = dev_dma;
> +
> + ops = dma_dev_ops(dev_dma);
> +
> + if (ops->of_xlate)
> + ret = ops->of_xlate(dma, );
> + else
> + ret = dma_of_xlate_default(dma, );
> + if (ret) {
> + pr_err("of_xlate() failed: %d\n", ret);
> + return ret;
> + }
> +
> + return dma_request(dev_dma, dma);
> +}
> +#  endif /* OF_PLATDATA */
> +
> +int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma)
> +{
> + int index;
> +
> + debug("%s(dev=%p, name=%s, dma=%p)\n", __func__, dev, name, dma);
> + dma->dev = NULL;
> +
> + index = dev_read_stringlist_search(dev, "dma-names", name);
> + if (index < 0) {
> + pr_err("dev_read_stringlist_search() failed: %d\n", index);
> 

Re: [U-Boot] [PATCH v5 02/15] dma: add channels support

2018-03-09 Thread Álvaro Fernández Rojas

Hi Grygorii,

El 09/03/2018 a las 0:07, Grygorii Strashko escribió:

Hi Álvaro,

On 03/05/2018 02:05 PM, Álvaro Fernández Rojas wrote:

This adds channels support for dma controllers that have multiple channels
which can transfer data to/from different devices (enet, usb...).

Signed-off-by: Álvaro Fernández Rojas 
Reviewed-by: Simon Glass 
---
   v5: remove unneeded dma.h include
   v4: no changes
   v3: Introduce changes reported by Simon Glass:
- Improve dma-uclass.h documentation.
- Switch to live tree API.

   drivers/dma/Kconfig  |   7 ++
   drivers/dma/dma-uclass.c | 188 
+--
   include/dma-uclass.h |  78 
   include/dma.h| 174 ++-
   4 files changed, 439 insertions(+), 8 deletions(-)

Small note first. I don't know if this is common practice for u-boot -
but Isn't it preferable to send new version of the series *not as reply* to the 
old one?
I was sending it as a reply to the first version, not the last one, but 
I will do that from now on.


I've tried this and, in general, it works for me (unfortunately I can't post 
code yet).
Thanks a lot for you work.

Thanks to you for testing :).


But... (it's always but ;)

¯\_(ツ)_/¯

[...]

+   /**
+* receive() - Receive a DMA transfer.
+*
+* @dma: The DMA Channel to manipulate.
+* @dst: The destination pointer.
+* @return zero on success, or -ve error code.
+*/
+   int (*receive)(struct dma *dma, void **dst);
+   /**
+* send() - Send a DMA transfer.
+*
+* @dma: The DMA Channel to manipulate.
+* @src: The source pointer.
+* @len: Length of the data to be sent (number of bytes).
+* @return zero on success, or -ve error code.
+*/
+   int (*send)(struct dma *dma, void *src, size_t len);

Can we have additional *optional* parameter in above two callbacks and in 
dma_receive/dma_send() API?
Like:
  int (*send)(struct dma *dma, void *src, size_t len, void *metadata)
  int (*receive)(struct dma *dma, void **dst, void **metadata);

Reason:
It's not a common practice to implement Networking DMA using generic DMA 
frameworks, simply
because Networking DMA HW is terribly different between different SoCs :(, so 
it's mostly impossible
to fit all of them in any generic DMA framework (at least this has never ever 
worked for Linux kernel):
- totally different HW rings/queues impl, multi-queues & multi DMA channels
- special requirements for IRQ handling
- necessity to pass additional information within each Net DMA descriptor
- availability and support of different Net traffic HW acceleration features

But in case of u-boot, it, theoretically, might work because most of Net
drivers have much more simplified implementation comparing to Linux kernel
- UP, polling, one RX/TX channel and disabled Net traffic HW acceleration 
features.

As result, Proposed here interface can be used with much more different HW and
drivers (and especially Net drivers), but only if it will be possible to pass
additional DMA driver's specific information from DMA user to DMA driver
per each send/rsv request.
For example, two TI driver cpsw.c and keystone_net.c required to pass
minimum one additional parameter with each sending packet - Destination Port 
number,
which must be passed to DMA in DMA descriptor. And Source Port number
has to be passed back with each received packet.

! I'm not insisting here ! and be happy to hear third opinion.

(if proposition will not be accepted - .. :( I'll just need to do the same 
later,
  but there might be hight number of active users of this interface in u-boot 
already)
If everyone else agrees I can add those two parameters in the next 
version even though my implementation doesn't need them.



+#endif /* CONFIG_DMA_CHANNELS */
/**
 * transfer() - Issue a DMA transfer. The implementation must
 *   wait until the transfer is done.
diff --git a/include/dma.h b/include/dma.h
index 89320f10d9..bf8123fa9e 100644
--- a/include/dma.h
+++ b/include/dma.h
@@ -1,6 +1,7 @@
   /*
- * (C) Copyright 2015
- * Texas Instruments Incorporated, 
+ * Copyright (C) 2018 Álvaro Fernández Rojas 
+ * Copyright (C) 2015 Texas Instruments Incorporated 
+ * Written by Mugunthan V N 
*
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -8,6 +9,9 @@
   #ifndef _DMA_H_
   #define _DMA_H_
   
+#include 

+#include 
+
   /*
* enum dma_direction - dma transfer direction indicator
* @DMA_MEM_TO_MEM: Memcpy mode
@@ -37,6 +41,172 @@ struct dma_dev_priv {
u32 supported;
   };
   
+#ifdef CONFIG_DMA_CHANNELS

+/**
+ * A DMA is a feature of computer systems that allows certain hardware
+ * subsystems to access main system memory, independent of the CPU.
+ * DMA channels are typically generated externally to the HW 

Re: [U-Boot] [PATCH v5 02/15] dma: add channels support

2018-03-08 Thread Grygorii Strashko
Hi Álvaro,

On 03/05/2018 02:05 PM, Álvaro Fernández Rojas wrote:
> This adds channels support for dma controllers that have multiple channels
> which can transfer data to/from different devices (enet, usb...).
> 
> Signed-off-by: Álvaro Fernández Rojas 
> Reviewed-by: Simon Glass 
> ---
>   v5: remove unneeded dma.h include
>   v4: no changes
>   v3: Introduce changes reported by Simon Glass:
>- Improve dma-uclass.h documentation.
>- Switch to live tree API.
> 
>   drivers/dma/Kconfig  |   7 ++
>   drivers/dma/dma-uclass.c | 188 
> +--
>   include/dma-uclass.h |  78 
>   include/dma.h| 174 ++-
>   4 files changed, 439 insertions(+), 8 deletions(-)

Small note first. I don't know if this is common practice for u-boot -
but Isn't it preferable to send new version of the series *not as reply* to the 
old one?

I've tried this and, in general, it works for me (unfortunately I can't post 
code yet).
Thanks a lot for you work.

But... (it's always but ;)
[...]
> + /**
> +  * receive() - Receive a DMA transfer.
> +  *
> +  * @dma: The DMA Channel to manipulate.
> +  * @dst: The destination pointer.
> +  * @return zero on success, or -ve error code.
> +  */
> + int (*receive)(struct dma *dma, void **dst);
> + /**
> +  * send() - Send a DMA transfer.
> +  *
> +  * @dma: The DMA Channel to manipulate.
> +  * @src: The source pointer.
> +  * @len: Length of the data to be sent (number of bytes).
> +  * @return zero on success, or -ve error code.
> +  */
> + int (*send)(struct dma *dma, void *src, size_t len);

Can we have additional *optional* parameter in above two callbacks and in 
dma_receive/dma_send() API?
Like:
 int (*send)(struct dma *dma, void *src, size_t len, void *metadata)
 int (*receive)(struct dma *dma, void **dst, void **metadata);

Reason:
It's not a common practice to implement Networking DMA using generic DMA 
frameworks, simply 
because Networking DMA HW is terribly different between different SoCs :(, so 
it's mostly impossible
to fit all of them in any generic DMA framework (at least this has never ever 
worked for Linux kernel):
- totally different HW rings/queues impl, multi-queues & multi DMA channels
- special requirements for IRQ handling
- necessity to pass additional information within each Net DMA descriptor
- availability and support of different Net traffic HW acceleration features

But in case of u-boot, it, theoretically, might work because most of Net
drivers have much more simplified implementation comparing to Linux kernel
- UP, polling, one RX/TX channel and disabled Net traffic HW acceleration 
features.

As result, Proposed here interface can be used with much more different HW and
drivers (and especially Net drivers), but only if it will be possible to pass
additional DMA driver's specific information from DMA user to DMA driver
per each send/rsv request.
For example, two TI driver cpsw.c and keystone_net.c required to pass
minimum one additional parameter with each sending packet - Destination Port 
number,
which must be passed to DMA in DMA descriptor. And Source Port number
has to be passed back with each received packet.

! I'm not insisting here ! and be happy to hear third opinion.

(if proposition will not be accepted - .. :( I'll just need to do the same 
later,
 but there might be hight number of active users of this interface in u-boot 
already)

> +#endif /* CONFIG_DMA_CHANNELS */
>   /**
>* transfer() - Issue a DMA transfer. The implementation must
>*   wait until the transfer is done.
> diff --git a/include/dma.h b/include/dma.h
> index 89320f10d9..bf8123fa9e 100644
> --- a/include/dma.h
> +++ b/include/dma.h
> @@ -1,6 +1,7 @@
>   /*
> - * (C) Copyright 2015
> - * Texas Instruments Incorporated, 
> + * Copyright (C) 2018 Álvaro Fernández Rojas 
> + * Copyright (C) 2015 Texas Instruments Incorporated 
> + * Written by Mugunthan V N 
>*
>* SPDX-License-Identifier: GPL-2.0+
>*/
> @@ -8,6 +9,9 @@
>   #ifndef _DMA_H_
>   #define _DMA_H_
>   
> +#include 
> +#include 
> +
>   /*
>* enum dma_direction - dma transfer direction indicator
>* @DMA_MEM_TO_MEM: Memcpy mode
> @@ -37,6 +41,172 @@ struct dma_dev_priv {
>   u32 supported;
>   };
>   
> +#ifdef CONFIG_DMA_CHANNELS
> +/**
> + * A DMA is a feature of computer systems that allows certain hardware
> + * subsystems to access main system memory, independent of the CPU.
> + * DMA channels are typically generated externally to the HW module
> + * consuming them, by an entity this API calls a DMA provider. This API
> + * provides a standard means for drivers to enable and disable DMAs, and to
> + * copy, send and receive data using DMA.
> + *
> + * A driver that implements UCLASS_DMA is a DMA 

Re: [U-Boot] [PATCH v5 02/15] dma: add channels support

2018-03-08 Thread Álvaro Fernández Rojas

Hi Joe,

El 07/03/2018 a las 22:27, Joe Hershberger escribió:

On Mon, Mar 5, 2018 at 2:05 PM, Álvaro Fernández Rojas
 wrote:

This adds channels support for dma controllers that have multiple channels
which can transfer data to/from different devices (enet, usb...).

Signed-off-by: Álvaro Fernández Rojas 
Reviewed-by: Simon Glass 
---
  v5: remove unneeded dma.h include
  v4: no changes
  v3: Introduce changes reported by Simon Glass:
   - Improve dma-uclass.h documentation.
   - Switch to live tree API.

  drivers/dma/Kconfig  |   7 ++
  drivers/dma/dma-uclass.c | 188 +--
  include/dma-uclass.h |  78 
  include/dma.h| 174 ++-
  4 files changed, 439 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 1b92c7789d..21b2c0dcaa 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -12,6 +12,13 @@ config DMA
   buses that is used to transfer data to and from memory.
   The uclass interface is defined in include/dma.h.

+config DMA_CHANNELS
+   bool "Enable DMA channels support"
+   depends on DMA
+   help
+ Enable channels support for DMA. Some DMA controllers have multiple
+ channels which can either transfer data to/from different devices.
+
  config TI_EDMA3
 bool "TI EDMA3 driver"
 help
diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
index faa27a3a56..b5109aafc9 100644
--- a/drivers/dma/dma-uclass.c
+++ b/drivers/dma/dma-uclass.c
@@ -1,23 +1,199 @@
  /*
   * Direct Memory Access U-Class driver
   *
- * (C) Copyright 2015
- * Texas Instruments Incorporated, 
- *
- * Author: Mugunthan V N 
+ * Copyright (C) 2018 Álvaro Fernández Rojas 
+ * Copyright (C) 2015 Texas Instruments Incorporated 
+ * Written by Mugunthan V N 
   *
   * SPDX-License-Identifier: GPL-2.0+
   */

  #include 
  #include 
-#include 
-#include 
+#include 
  #include 
+#include 
  #include 

  DECLARE_GLOBAL_DATA_PTR;

+#ifdef CONFIG_DMA_CHANNELS
+static inline struct dma_ops *dma_dev_ops(struct udevice *dev)
+{
+   return (struct dma_ops *)dev->driver->ops;
+}
+
+# if CONFIG_IS_ENABLED(OF_CONTROL)
+#  if CONFIG_IS_ENABLED(OF_PLATDATA)
+int dma_get_by_index_platdata(struct udevice *dev, int index,
+ struct phandle_1_arg *cells, struct dma *dma)
+{
+   int ret;
+
+   if (index != 0)
+   return -ENOSYS;
+   ret = uclass_get_device(UCLASS_DMA, 0, >dev);
+   if (ret)
+   return ret;
+   dma->id = cells[0].id;
+
+   return 0;
+}
+#  else
+static int dma_of_xlate_default(struct dma *dma,
+   struct ofnode_phandle_args *args)
+{
+   debug("%s(dma=%p)\n", __func__, dma);
+
+   if (args->args_count > 1) {
+   pr_err("Invaild args_count: %d\n", args->args_count);
+   return -EINVAL;
+   }
+
+   if (args->args_count)
+   dma->id = args->args[0];
+   else
+   dma->id = 0;
+
+   return 0;
+}
+
+int dma_get_by_index(struct udevice *dev, int index, struct dma *dma)
+{
+   int ret;
+   struct ofnode_phandle_args args;
+   struct udevice *dev_dma;
+   const struct dma_ops *ops;
+
+   debug("%s(dev=%p, index=%d, dma=%p)\n", __func__, dev, index, dma);
+
+   assert(dma);
+   dma->dev = NULL;
+
+   ret = dev_read_phandle_with_args(dev, "dmas", "#dma-cells", 0, index,
+);
+   if (ret) {
+   pr_err("%s: dev_read_phandle_with_args failed: err=%d\n",
+  __func__, ret);
+   return ret;
+   }
+
+   ret = uclass_get_device_by_ofnode(UCLASS_DMA, args.node, _dma);
+   if (ret) {
+   pr_err("%s: uclass_get_device_by_ofnode failed: err=%d\n",
+  __func__, ret);
+   return ret;
+   }
+
+   dma->dev = dev_dma;
+
+   ops = dma_dev_ops(dev_dma);
+
+   if (ops->of_xlate)
+   ret = ops->of_xlate(dma, );
+   else
+   ret = dma_of_xlate_default(dma, );
+   if (ret) {
+   pr_err("of_xlate() failed: %d\n", ret);
+   return ret;
+   }
+
+   return dma_request(dev_dma, dma);
+}
+#  endif /* OF_PLATDATA */
+
+int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma)
+{
+   int index;
+
+   debug("%s(dev=%p, name=%s, dma=%p)\n", __func__, dev, name, dma);
+   dma->dev = NULL;
+
+   index = dev_read_stringlist_search(dev, "dma-names", name);
+   if (index < 0) {
+   pr_err("dev_read_stringlist_search() failed: %d\n", index);
+   return index;
+   }
+
+   return dma_get_by_index(dev, index, dma);
+}
+# endif /* 

Re: [U-Boot] [PATCH v5 02/15] dma: add channels support

2018-03-07 Thread Joe Hershberger
On Mon, Mar 5, 2018 at 2:05 PM, Álvaro Fernández Rojas
 wrote:
> This adds channels support for dma controllers that have multiple channels
> which can transfer data to/from different devices (enet, usb...).
>
> Signed-off-by: Álvaro Fernández Rojas 
> Reviewed-by: Simon Glass 
> ---
>  v5: remove unneeded dma.h include
>  v4: no changes
>  v3: Introduce changes reported by Simon Glass:
>   - Improve dma-uclass.h documentation.
>   - Switch to live tree API.
>
>  drivers/dma/Kconfig  |   7 ++
>  drivers/dma/dma-uclass.c | 188 
> +--
>  include/dma-uclass.h |  78 
>  include/dma.h| 174 ++-
>  4 files changed, 439 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
> index 1b92c7789d..21b2c0dcaa 100644
> --- a/drivers/dma/Kconfig
> +++ b/drivers/dma/Kconfig
> @@ -12,6 +12,13 @@ config DMA
>   buses that is used to transfer data to and from memory.
>   The uclass interface is defined in include/dma.h.
>
> +config DMA_CHANNELS
> +   bool "Enable DMA channels support"
> +   depends on DMA
> +   help
> + Enable channels support for DMA. Some DMA controllers have multiple
> + channels which can either transfer data to/from different devices.
> +
>  config TI_EDMA3
> bool "TI EDMA3 driver"
> help
> diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
> index faa27a3a56..b5109aafc9 100644
> --- a/drivers/dma/dma-uclass.c
> +++ b/drivers/dma/dma-uclass.c
> @@ -1,23 +1,199 @@
>  /*
>   * Direct Memory Access U-Class driver
>   *
> - * (C) Copyright 2015
> - * Texas Instruments Incorporated, 
> - *
> - * Author: Mugunthan V N 
> + * Copyright (C) 2018 Álvaro Fernández Rojas 
> + * Copyright (C) 2015 Texas Instruments Incorporated 
> + * Written by Mugunthan V N 
>   *
>   * SPDX-License-Identifier: GPL-2.0+
>   */
>
>  #include 
>  #include 
> -#include 
> -#include 
> +#include 
>  #include 
> +#include 
>  #include 
>
>  DECLARE_GLOBAL_DATA_PTR;
>
> +#ifdef CONFIG_DMA_CHANNELS
> +static inline struct dma_ops *dma_dev_ops(struct udevice *dev)
> +{
> +   return (struct dma_ops *)dev->driver->ops;
> +}
> +
> +# if CONFIG_IS_ENABLED(OF_CONTROL)
> +#  if CONFIG_IS_ENABLED(OF_PLATDATA)
> +int dma_get_by_index_platdata(struct udevice *dev, int index,
> + struct phandle_1_arg *cells, struct dma *dma)
> +{
> +   int ret;
> +
> +   if (index != 0)
> +   return -ENOSYS;
> +   ret = uclass_get_device(UCLASS_DMA, 0, >dev);
> +   if (ret)
> +   return ret;
> +   dma->id = cells[0].id;
> +
> +   return 0;
> +}
> +#  else
> +static int dma_of_xlate_default(struct dma *dma,
> +   struct ofnode_phandle_args *args)
> +{
> +   debug("%s(dma=%p)\n", __func__, dma);
> +
> +   if (args->args_count > 1) {
> +   pr_err("Invaild args_count: %d\n", args->args_count);
> +   return -EINVAL;
> +   }
> +
> +   if (args->args_count)
> +   dma->id = args->args[0];
> +   else
> +   dma->id = 0;
> +
> +   return 0;
> +}
> +
> +int dma_get_by_index(struct udevice *dev, int index, struct dma *dma)
> +{
> +   int ret;
> +   struct ofnode_phandle_args args;
> +   struct udevice *dev_dma;
> +   const struct dma_ops *ops;
> +
> +   debug("%s(dev=%p, index=%d, dma=%p)\n", __func__, dev, index, dma);
> +
> +   assert(dma);
> +   dma->dev = NULL;
> +
> +   ret = dev_read_phandle_with_args(dev, "dmas", "#dma-cells", 0, index,
> +);
> +   if (ret) {
> +   pr_err("%s: dev_read_phandle_with_args failed: err=%d\n",
> +  __func__, ret);
> +   return ret;
> +   }
> +
> +   ret = uclass_get_device_by_ofnode(UCLASS_DMA, args.node, _dma);
> +   if (ret) {
> +   pr_err("%s: uclass_get_device_by_ofnode failed: err=%d\n",
> +  __func__, ret);
> +   return ret;
> +   }
> +
> +   dma->dev = dev_dma;
> +
> +   ops = dma_dev_ops(dev_dma);
> +
> +   if (ops->of_xlate)
> +   ret = ops->of_xlate(dma, );
> +   else
> +   ret = dma_of_xlate_default(dma, );
> +   if (ret) {
> +   pr_err("of_xlate() failed: %d\n", ret);
> +   return ret;
> +   }
> +
> +   return dma_request(dev_dma, dma);
> +}
> +#  endif /* OF_PLATDATA */
> +
> +int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma)
> +{
> +   int index;
> +
> +   debug("%s(dev=%p, name=%s, dma=%p)\n", __func__, dev, name, dma);
> +   dma->dev = NULL;
> +
> +   index = dev_read_stringlist_search(dev, "dma-names", 

[U-Boot] [PATCH v5 02/15] dma: add channels support

2018-03-05 Thread Álvaro Fernández Rojas
This adds channels support for dma controllers that have multiple channels
which can transfer data to/from different devices (enet, usb...).

Signed-off-by: Álvaro Fernández Rojas 
Reviewed-by: Simon Glass 
---
 v5: remove unneeded dma.h include
 v4: no changes
 v3: Introduce changes reported by Simon Glass:
  - Improve dma-uclass.h documentation.
  - Switch to live tree API.

 drivers/dma/Kconfig  |   7 ++
 drivers/dma/dma-uclass.c | 188 +--
 include/dma-uclass.h |  78 
 include/dma.h| 174 ++-
 4 files changed, 439 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 1b92c7789d..21b2c0dcaa 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -12,6 +12,13 @@ config DMA
  buses that is used to transfer data to and from memory.
  The uclass interface is defined in include/dma.h.
 
+config DMA_CHANNELS
+   bool "Enable DMA channels support"
+   depends on DMA
+   help
+ Enable channels support for DMA. Some DMA controllers have multiple
+ channels which can either transfer data to/from different devices.
+
 config TI_EDMA3
bool "TI EDMA3 driver"
help
diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
index faa27a3a56..b5109aafc9 100644
--- a/drivers/dma/dma-uclass.c
+++ b/drivers/dma/dma-uclass.c
@@ -1,23 +1,199 @@
 /*
  * Direct Memory Access U-Class driver
  *
- * (C) Copyright 2015
- * Texas Instruments Incorporated, 
- *
- * Author: Mugunthan V N 
+ * Copyright (C) 2018 Álvaro Fernández Rojas 
+ * Copyright (C) 2015 Texas Instruments Incorporated 
+ * Written by Mugunthan V N 
  *
  * SPDX-License-Identifier: GPL-2.0+
  */
 
 #include 
 #include 
-#include 
-#include 
+#include 
 #include 
+#include 
 #include 
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifdef CONFIG_DMA_CHANNELS
+static inline struct dma_ops *dma_dev_ops(struct udevice *dev)
+{
+   return (struct dma_ops *)dev->driver->ops;
+}
+
+# if CONFIG_IS_ENABLED(OF_CONTROL)
+#  if CONFIG_IS_ENABLED(OF_PLATDATA)
+int dma_get_by_index_platdata(struct udevice *dev, int index,
+ struct phandle_1_arg *cells, struct dma *dma)
+{
+   int ret;
+
+   if (index != 0)
+   return -ENOSYS;
+   ret = uclass_get_device(UCLASS_DMA, 0, >dev);
+   if (ret)
+   return ret;
+   dma->id = cells[0].id;
+
+   return 0;
+}
+#  else
+static int dma_of_xlate_default(struct dma *dma,
+   struct ofnode_phandle_args *args)
+{
+   debug("%s(dma=%p)\n", __func__, dma);
+
+   if (args->args_count > 1) {
+   pr_err("Invaild args_count: %d\n", args->args_count);
+   return -EINVAL;
+   }
+
+   if (args->args_count)
+   dma->id = args->args[0];
+   else
+   dma->id = 0;
+
+   return 0;
+}
+
+int dma_get_by_index(struct udevice *dev, int index, struct dma *dma)
+{
+   int ret;
+   struct ofnode_phandle_args args;
+   struct udevice *dev_dma;
+   const struct dma_ops *ops;
+
+   debug("%s(dev=%p, index=%d, dma=%p)\n", __func__, dev, index, dma);
+
+   assert(dma);
+   dma->dev = NULL;
+
+   ret = dev_read_phandle_with_args(dev, "dmas", "#dma-cells", 0, index,
+);
+   if (ret) {
+   pr_err("%s: dev_read_phandle_with_args failed: err=%d\n",
+  __func__, ret);
+   return ret;
+   }
+
+   ret = uclass_get_device_by_ofnode(UCLASS_DMA, args.node, _dma);
+   if (ret) {
+   pr_err("%s: uclass_get_device_by_ofnode failed: err=%d\n",
+  __func__, ret);
+   return ret;
+   }
+
+   dma->dev = dev_dma;
+
+   ops = dma_dev_ops(dev_dma);
+
+   if (ops->of_xlate)
+   ret = ops->of_xlate(dma, );
+   else
+   ret = dma_of_xlate_default(dma, );
+   if (ret) {
+   pr_err("of_xlate() failed: %d\n", ret);
+   return ret;
+   }
+
+   return dma_request(dev_dma, dma);
+}
+#  endif /* OF_PLATDATA */
+
+int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma)
+{
+   int index;
+
+   debug("%s(dev=%p, name=%s, dma=%p)\n", __func__, dev, name, dma);
+   dma->dev = NULL;
+
+   index = dev_read_stringlist_search(dev, "dma-names", name);
+   if (index < 0) {
+   pr_err("dev_read_stringlist_search() failed: %d\n", index);
+   return index;
+   }
+
+   return dma_get_by_index(dev, index, dma);
+}
+# endif /* OF_CONTROL */
+
+int dma_request(struct udevice *dev, struct dma *dma)
+{
+   struct dma_ops *ops = dma_dev_ops(dev);
+
+   debug("%s(dev=%p, dma=%p)\n", __func__, dev,