From mboxrd@z Thu Jan 1 00:00:00 1970 From: =?UTF-8?Q?=c3=81lvaro_Fern=c3=a1ndez_Rojas?= Date: Wed, 21 Feb 2018 16:51:40 +0100 Subject: [U-Boot] [RFC v2 02/15] dma: add channels support In-Reply-To: References: <20180212163858.25601-1-noltari@gmail.com> <20180220174657.4000-1-noltari@gmail.com> <20180220174657.4000-3-noltari@gmail.com> Message-ID: <31a18cc3-6fff-9d38-3bcf-837cc4a3dae7@gmail.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit To: u-boot@lists.denx.de Hi Simon, El 20/02/2018 a las 19:49, Simon Glass escribió: > Hi Alvaro, > > On 20 February 2018 at 10:46, Á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 >> --- >> v2: Introduce changes reported by Vignesh: >> - Respect current dma implementation. >> - Let dma_memcpy find a compatible dma device. >> >> drivers/dma/Kconfig | 7 ++ >> drivers/dma/dma-uclass.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++ >> include/dma-uclass.h | 77 +++++++++++++++++++++ >> include/dma.h | 169 ++++++++++++++++++++++++++++++++++++++++++++ >> 4 files changed, 430 insertions(+) >> >> 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 6fd4e1b35d..a16c3a786c 100644 >> --- a/drivers/dma/dma-uclass.c >> +++ b/drivers/dma/dma-uclass.c >> @@ -15,10 +15,187 @@ >> #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_2_cell *cells, struct dma *dma) >> +{ >> + int ret; >> + >> + if (index != 0) >> + return -ENOSYS; >> + ret = uclass_get_device(UCLASS_DMA, 0, &dma->dev); >> + if (ret) >> + return ret; >> + dma->id = cells[0].id; >> + >> + return 0; >> +} >> +# else >> +static int dma_of_xlate_default(struct dma *dma, >> + struct fdtdec_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 fdtdec_phandle_args args; >> + struct udevice *dev_dma; >> + struct dma_ops *ops; >> + >> + debug("%s(dev=%p, index=%d, dma=%p)\n", __func__, dev, index, dma); >> + >> + assert(dma); >> + ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev), >> + "dmas", "#dma-cells", 0, index, >> + &args); > Can you please use the livetree API? E.g. see dev_read_phandle_with_args() > > Also please move this into an ofdata_to_platdata function rather than > doing it each time this function is called. I don't really get what you mean by moving this into an ofdata_to_platdata function. This code is copied from other uclasses: https://github.com/Noltari/u-boot/blob/master/drivers/clk/clk-uclass.c#L71 https://github.com/Noltari/u-boot/blob/master/drivers/power/domain/power-domain-uclass.c#L43 https://github.com/Noltari/u-boot/blob/master/drivers/reset/reset-uclass.c#L47 > >> + if (ret) { >> + pr_err("%s: fdtdec_parse_phandle_with_args failed: err=%d\n", >> + __func__, ret); >> + return ret; >> + } >> + >> + ret = uclass_get_device_by_of_offset(UCLASS_DMA, args.node, &dev_dma); >> + if (ret) { >> + pr_err("%s: uclass_get_device_by_of_offset 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, &args); >> + else >> + ret = dma_of_xlate_default(dma, &args); >> + 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); >> + >> + index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev), >> + "dma-names", name); > dev_read... > >> + if (index < 0) { >> + pr_err("fdt_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, dma); >> + >> + dma->dev = dev; >> + >> + if (!ops->request) >> + return 0; >> + >> + return ops->request(dma); >> +} >> + >> +int dma_free(struct dma *dma) >> +{ >> + struct dma_ops *ops = dma_dev_ops(dma->dev); >> + >> + debug("%s(dma=%p)\n", __func__, dma); >> + >> + if (!ops->free) >> + return 0; >> + >> + return ops->free(dma); >> +} >> + >> +int dma_enable(struct dma *dma) >> +{ >> + struct dma_ops *ops = dma_dev_ops(dma->dev); >> + >> + debug("%s(dma=%p)\n", __func__, dma); >> + >> + if (!ops->enable) >> + return -ENOSYS; >> + >> + return ops->enable(dma); >> +} >> + >> +int dma_disable(struct dma *dma) >> +{ >> + struct dma_ops *ops = dma_dev_ops(dma->dev); >> + >> + debug("%s(dma=%p)\n", __func__, dma); >> + >> + if (!ops->disable) >> + return -ENOSYS; >> + >> + return ops->disable(dma); >> +} >> + >> +int dma_receive(struct dma *dma, void **dst) >> +{ >> + struct dma_ops *ops = dma_dev_ops(dma->dev); >> + >> + debug("%s(dma=%p)\n", __func__, dma); >> + >> + if (!ops->receive) >> + return -1; >> + >> + return ops->receive(dma, dst); >> +} >> + >> +int dma_send(struct dma *dma, void *src, size_t len) >> +{ >> + struct dma_ops *ops = dma_dev_ops(dma->dev); >> + >> + debug("%s(dma=%p)\n", __func__, dma); >> + >> + if (!ops->send) >> + return -1; >> + >> + return ops->send(dma, src, len); >> +} >> +#endif /* CONFIG_DMA_CHANNELS */ >> + >> int dma_get_device(u32 transfer_type, struct udevice **devp) >> { >> struct udevice *dev; >> diff --git a/include/dma-uclass.h b/include/dma-uclass.h >> index e29ad103f2..5faec69207 100644 >> --- a/include/dma-uclass.h >> +++ b/include/dma-uclass.h >> @@ -12,6 +12,7 @@ >> /* See dma.h for background documentation. */ >> >> #include >> +#include >> >> /* >> * struct dma_ops - Driver model DMA operations >> @@ -20,6 +21,82 @@ >> * driver model. >> */ >> struct dma_ops { >> +#ifdef CONFIG_DMA_CHANNELS >> + /** >> + * of_xlate - Translate a client's device-tree (OF) DMA specifier. >> + * >> + * The DMA core calls this function as the first step in implementing >> + * a client's dma_get_by_*() call. >> + * >> + * If this function pointer is set to NULL, the DMA core will use a >> + * default implementation, which assumes #dma-cells = <1>, and that >> + * the DT cell contains a simple integer DMA Channel. >> + * >> + * At present, the DMA API solely supports device-tree. If this >> + * changes, other xxx_xlate() functions may be added to support those >> + * other mechanisms. >> + * >> + * @dma: The dma struct to hold the translation result. >> + * @args: The dma specifier values from device tree. >> + * @return 0 if OK, or a negative error code. >> + */ >> + int (*of_xlate)(struct dma *dma, >> + struct fdtdec_phandle_args *args); > Use new livetree struct here > > Regards, > Simon Regards, Álvaro.