Message ID | 1448968398-8270-2-git-send-email-mugunthanvnm@ti.com |
---|---|
State | Changes Requested |
Delegated to: | Tom Rini |
Headers | show |
Hi Mugunthan, On 1 December 2015 at 04:13, Mugunthan V N <mugunthanvnm@ti.com> wrote: > Implement a DMA uclass so that the devices like ethernet, spi, > mmc etc can offload the data transfers from/to the device and > memory. > > Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> > --- > drivers/dma/Kconfig | 15 ++++++++++++ > drivers/dma/Makefile | 2 ++ > drivers/dma/dma-uclass.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ > include/dm/uclass-id.h | 1 + > include/dma.h | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 145 insertions(+) > create mode 100644 drivers/dma/dma-uclass.c > create mode 100644 include/dma.h > > diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig > index e69de29..af15199 100644 > --- a/drivers/dma/Kconfig > +++ b/drivers/dma/Kconfig > @@ -0,0 +1,15 @@ > +menu "DMA Support" > + > +config DM_DMA > + bool "Enable Driver Model for DMA drivers" > + depends on DM > + help > + Enable driver model for DMA. DMA engines can do > + asynchronous data transfers without involving the host > + CPU. Currently, this framework can be used to offload > + memory copies to and from devices like qspi, ethernet > + etc Drivers provide methods to access the DMA devices > + buses that is used to transfer data to and from memory. > + The uclass interface is defined in include/dma.h. > + > +endmenu # menu "DMA Support" > diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile > index f95fe70..4ff22aa 100644 > --- a/drivers/dma/Makefile > +++ b/drivers/dma/Makefile > @@ -5,6 +5,8 @@ > # SPDX-License-Identifier: GPL-2.0+ > # > > +obj-$(CONFIG_DM_DMA) += dma-uclass.o You can just use CONFIG_DMA. The DM_ prefix is for when we have an existing pre-DM interface. Eventually all the CONFIG_DM_... options will be removed. Unless you have a special reason? > + > obj-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o > obj-$(CONFIG_APBH_DMA) += apbh_dma.o > obj-$(CONFIG_FSL_DMA) += fsl_dma.o > diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c > new file mode 100644 > index 0000000..1afcbaa4 > --- /dev/null > +++ b/drivers/dma/dma-uclass.c > @@ -0,0 +1,63 @@ > +/* > + * Direct Memory Access U-Class driver > + * > + * (C) Copyright 2015 > + * Texas Instruments Incorporated, <www.ti.com> > + * > + * Author: Mugunthan V N <mugunthanvnm@ti.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <dma.h> > +#include <dm.h> > +#include <dm/uclass-internal.h> > +#include <errno.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +int dma_memcpy(void *dst, void *src, size_t len) > +{ > + struct udevice *dev; > + const struct dma_ops *ops; > + int ret; > + > + for (ret = uclass_find_first_device(UCLASS_DMA, &dev); dev && !ret; > + ret = uclass_find_next_device(&dev)) { > + struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev); > + > + if (uc_priv->supported & SUPPORTS_MEM_TO_MEM) > + break; > + } > + > + if (!dev) { > + printf("No DMA device found that supports mem to mem transfers\n"); > + return -ENODEV; > + } Can you put the above code in a separate function like: static int get_dma_device(struct udevice **devp) also also please call device_probe() on it before returning it. > + > + ops = device_get_ops(dev); > + if (!ops->transfer) > + return -ENOSYS; > + > + /* Invalidate the area, so no writeback into the RAM races with DMA */ > + invalidate_dcache_range((unsigned long)dst, (unsigned long)dst + > + roundup(len, ARCH_DMA_MINALIGN)); > + > + return ops->transfer(dev, DMA_MEM_TO_MEM, dst, src, len); > +} > + > +int dma_post_bind(struct udevice *dev) > +{ > + struct udevice *devp; > + uclass_get_device_by_of_offset(UCLASS_DMA, dev->of_offset, &devp); You are not allowed to do this in the post_bind() method. See above for how it should get probed. > + return 0; > +} > + > +UCLASS_DRIVER(dma) = { > + .id = UCLASS_DMA, > + .name = "dma", > + .flags = DM_UC_FLAG_SEQ_ALIAS, > + .per_device_auto_alloc_size = sizeof(struct dma_dev_priv), > + .post_bind = dma_post_bind, > +}; > diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h > index 27fa0b6..9f5fcae 100644 > --- a/include/dm/uclass-id.h > +++ b/include/dm/uclass-id.h > @@ -30,6 +30,7 @@ enum uclass_id { > UCLASS_CPU, /* CPU, typically part of an SoC */ > UCLASS_CROS_EC, /* Chrome OS EC */ > UCLASS_DISPLAY_PORT, /* Display port video */ > + UCLASS_DMA, /* Direct Memory Access */ > UCLASS_RAM, /* RAM controller */ > UCLASS_ETH, /* Ethernet device */ > UCLASS_GPIO, /* Bank of general-purpose I/O pins */ > diff --git a/include/dma.h b/include/dma.h > new file mode 100644 > index 0000000..d53e435 > --- /dev/null > +++ b/include/dma.h > @@ -0,0 +1,64 @@ > +/* > + * (C) Copyright 2015 > + * Texas Instruments Incorporated, <www.ti.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#ifndef _DMA_H_ > +#define _DMA_H_ > + > +/* > + * enum dma_direction - dma transfer direction indicator > + * @DMA_MEM_TO_MEM: Memcpy mode > + * @DMA_MEM_TO_DEV: From Memory to Device > + * @DMA_DEV_TO_MEM: From Device to Memory > + * @DMA_DEV_TO_DEV: From Device to Device > + */ > +enum dma_direction { > + DMA_MEM_TO_MEM, > + DMA_MEM_TO_DEV, > + DMA_DEV_TO_MEM, > + DMA_DEV_TO_DEV, > + DMA_TRANS_NONE, What does that mean? > +}; > + > +#define SUPPORTS_MEM_TO_MEM BIT(0) > +#define SUPPORTS_MEM_TO_DEV BIT(1) > +#define SUPPORTS_DEV_TO_MEM BIT(2) > +#define SUPPORTS_DEV_TO_DEV BIT(3) DMA_ prefix on these. Also you could put them in an enum so they are grouped. > + > +/* > + * struct dma_ops - Driver model DMA operations > + * > + * The uclass interface is implemented by all DMA devices which use > + * driver model. > + */ > +struct dma_ops { > + /* > + * Get the current timer count Incorrect comment. > + * > + * @dev: The DMA device > + * @direction: direction of data transfer should be one from > + enum dma_direction > + * @dst: Destination pointer > + * @src: Source pointer Any alignment restructions? > + * @len: Length of the data to be copied. In bytes? > + * @return: 0 if OK, -ve on error > + */ > + int (*transfer)(struct udevice *dev, int direction, void *dst, s/int direction/enum dma_direction direction/ > + void *src, size_t len); > +}; > + > +/* > + * struct dma_dev_priv - information about a device used by the uclass > + * > + * @supported: mode of transfers that DMA can support Please reference where these flags come from. > + */ > +struct dma_dev_priv { > + unsigned long supported; int or uint should be enough. > +}; > + > +int dma_memcpy(void *dst, void *src, size_t len); > + > +#endif /* _DMA_H_ */ > -- > 2.6.3.368.gf34be46 > Regards, Simon
On Wednesday 02 December 2015 03:24 AM, Simon Glass wrote: > Hi Mugunthan, > > On 1 December 2015 at 04:13, Mugunthan V N <mugunthanvnm@ti.com> wrote: >> Implement a DMA uclass so that the devices like ethernet, spi, >> mmc etc can offload the data transfers from/to the device and >> memory. >> >> Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> >> --- >> drivers/dma/Kconfig | 15 ++++++++++++ >> drivers/dma/Makefile | 2 ++ >> drivers/dma/dma-uclass.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ >> include/dm/uclass-id.h | 1 + >> include/dma.h | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ >> 5 files changed, 145 insertions(+) >> create mode 100644 drivers/dma/dma-uclass.c >> create mode 100644 include/dma.h >> >> diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig >> index e69de29..af15199 100644 >> --- a/drivers/dma/Kconfig >> +++ b/drivers/dma/Kconfig >> @@ -0,0 +1,15 @@ >> +menu "DMA Support" >> + >> +config DM_DMA >> + bool "Enable Driver Model for DMA drivers" >> + depends on DM >> + help >> + Enable driver model for DMA. DMA engines can do >> + asynchronous data transfers without involving the host >> + CPU. Currently, this framework can be used to offload >> + memory copies to and from devices like qspi, ethernet >> + etc Drivers provide methods to access the DMA devices >> + buses that is used to transfer data to and from memory. >> + The uclass interface is defined in include/dma.h. >> + >> +endmenu # menu "DMA Support" >> diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile >> index f95fe70..4ff22aa 100644 >> --- a/drivers/dma/Makefile >> +++ b/drivers/dma/Makefile >> @@ -5,6 +5,8 @@ >> # SPDX-License-Identifier: GPL-2.0+ >> # >> >> +obj-$(CONFIG_DM_DMA) += dma-uclass.o > > You can just use CONFIG_DMA. The DM_ prefix is for when we have an > existing pre-DM interface. Eventually all the CONFIG_DM_... options > will be removed. Unless you have a special reason? For consistency I used CONFIG_DM_DMA, will rename it to CONFIG_DMA. > >> + >> obj-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o >> obj-$(CONFIG_APBH_DMA) += apbh_dma.o >> obj-$(CONFIG_FSL_DMA) += fsl_dma.o >> diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c >> new file mode 100644 >> index 0000000..1afcbaa4 >> --- /dev/null >> +++ b/drivers/dma/dma-uclass.c >> @@ -0,0 +1,63 @@ >> +/* >> + * Direct Memory Access U-Class driver >> + * >> + * (C) Copyright 2015 >> + * Texas Instruments Incorporated, <www.ti.com> >> + * >> + * Author: Mugunthan V N <mugunthanvnm@ti.com> >> + * >> + * SPDX-License-Identifier: GPL-2.0+ >> + */ >> + >> +#include <common.h> >> +#include <dma.h> >> +#include <dm.h> >> +#include <dm/uclass-internal.h> >> +#include <errno.h> >> + >> +DECLARE_GLOBAL_DATA_PTR; >> + >> +int dma_memcpy(void *dst, void *src, size_t len) >> +{ >> + struct udevice *dev; >> + const struct dma_ops *ops; >> + int ret; >> + >> + for (ret = uclass_find_first_device(UCLASS_DMA, &dev); dev && !ret; >> + ret = uclass_find_next_device(&dev)) { >> + struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev); >> + >> + if (uc_priv->supported & SUPPORTS_MEM_TO_MEM) >> + break; >> + } >> + >> + if (!dev) { >> + printf("No DMA device found that supports mem to mem transfers\n"); >> + return -ENODEV; >> + } > > Can you put the above code in a separate function like: > > static int get_dma_device(struct udevice **devp) > > also also please call device_probe() on it before returning it. Okay, will do it in next version. > >> + >> + ops = device_get_ops(dev); >> + if (!ops->transfer) >> + return -ENOSYS; >> + >> + /* Invalidate the area, so no writeback into the RAM races with DMA */ >> + invalidate_dcache_range((unsigned long)dst, (unsigned long)dst + >> + roundup(len, ARCH_DMA_MINALIGN)); >> + >> + return ops->transfer(dev, DMA_MEM_TO_MEM, dst, src, len); >> +} >> + >> +int dma_post_bind(struct udevice *dev) >> +{ >> + struct udevice *devp; >> + uclass_get_device_by_of_offset(UCLASS_DMA, dev->of_offset, &devp); > > You are not allowed to do this in the post_bind() method. See above > for how it should get probed. > Okay, agreed. >> + return 0; >> +} >> + >> +UCLASS_DRIVER(dma) = { >> + .id = UCLASS_DMA, >> + .name = "dma", >> + .flags = DM_UC_FLAG_SEQ_ALIAS, >> + .per_device_auto_alloc_size = sizeof(struct dma_dev_priv), >> + .post_bind = dma_post_bind, >> +}; >> diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h >> index 27fa0b6..9f5fcae 100644 >> --- a/include/dm/uclass-id.h >> +++ b/include/dm/uclass-id.h >> @@ -30,6 +30,7 @@ enum uclass_id { >> UCLASS_CPU, /* CPU, typically part of an SoC */ >> UCLASS_CROS_EC, /* Chrome OS EC */ >> UCLASS_DISPLAY_PORT, /* Display port video */ >> + UCLASS_DMA, /* Direct Memory Access */ >> UCLASS_RAM, /* RAM controller */ >> UCLASS_ETH, /* Ethernet device */ >> UCLASS_GPIO, /* Bank of general-purpose I/O pins */ >> diff --git a/include/dma.h b/include/dma.h >> new file mode 100644 >> index 0000000..d53e435 >> --- /dev/null >> +++ b/include/dma.h >> @@ -0,0 +1,64 @@ >> +/* >> + * (C) Copyright 2015 >> + * Texas Instruments Incorporated, <www.ti.com> >> + * >> + * SPDX-License-Identifier: GPL-2.0+ >> + */ >> + >> +#ifndef _DMA_H_ >> +#define _DMA_H_ >> + >> +/* >> + * enum dma_direction - dma transfer direction indicator >> + * @DMA_MEM_TO_MEM: Memcpy mode >> + * @DMA_MEM_TO_DEV: From Memory to Device >> + * @DMA_DEV_TO_MEM: From Device to Memory >> + * @DMA_DEV_TO_DEV: From Device to Device >> + */ >> +enum dma_direction { >> + DMA_MEM_TO_MEM, >> + DMA_MEM_TO_DEV, >> + DMA_DEV_TO_MEM, >> + DMA_DEV_TO_DEV, >> + DMA_TRANS_NONE, > > What does that mean? DMA driver will be having only one transfer api and to identify what kind of transfer that the user driver is expecting, these enums are used. > >> +}; >> + >> +#define SUPPORTS_MEM_TO_MEM BIT(0) >> +#define SUPPORTS_MEM_TO_DEV BIT(1) >> +#define SUPPORTS_DEV_TO_MEM BIT(2) >> +#define SUPPORTS_DEV_TO_DEV BIT(3) > > DMA_ prefix on these. Also you could put them in an enum so they are grouped. Will add DMA prefix to these defines. Since a dma driver can support multiple transfer types I kept this as bit level definitions, so that driver can intimate DMA framework like uc_priv->supported = SUPPORTS_MEM_TO_MEM | SUPPORTS_MEM_TO_DEV; > >> + >> +/* >> + * struct dma_ops - Driver model DMA operations >> + * >> + * The uclass interface is implemented by all DMA devices which use >> + * driver model. >> + */ >> +struct dma_ops { >> + /* >> + * Get the current timer count > > Incorrect comment. > >> + * >> + * @dev: The DMA device >> + * @direction: direction of data transfer should be one from >> + enum dma_direction >> + * @dst: Destination pointer >> + * @src: Source pointer > > Any alignment restructions? I should be aligned to DMA device alignment restrictions. > >> + * @len: Length of the data to be copied. > > In bytes? Okay > >> + * @return: 0 if OK, -ve on error >> + */ >> + int (*transfer)(struct udevice *dev, int direction, void *dst, > > s/int direction/enum dma_direction direction/ Okay > >> + void *src, size_t len); >> +}; >> + >> +/* >> + * struct dma_dev_priv - information about a device used by the uclass >> + * >> + * @supported: mode of transfers that DMA can support > > Please reference where these flags come from. Okay > >> + */ >> +struct dma_dev_priv { >> + unsigned long supported; > > int or uint should be enough. Will used uint. > >> +}; >> + >> +int dma_memcpy(void *dst, void *src, size_t len); >> + >> +#endif /* _DMA_H_ */ >> -- >> 2.6.3.368.gf34be46 >> > > Regards, > Simon > Regards Mugunthan V N
On Wednesday 02 December 2015 01:47 PM, Mugunthan V N wrote: >>> + DMA_TRANS_NONE, >> > >> > What does that mean? > DMA driver will be having only one transfer api and to identify what > kind of transfer that the user driver is expecting, these enums are used. > Oops, I was taking your comment for the whole enums. Thought of having an error enum as DMA_TRANS_NONE, but it doesn't add value, will remove it in next version. Regards Mugunthan V N
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index e69de29..af15199 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -0,0 +1,15 @@ +menu "DMA Support" + +config DM_DMA + bool "Enable Driver Model for DMA drivers" + depends on DM + help + Enable driver model for DMA. DMA engines can do + asynchronous data transfers without involving the host + CPU. Currently, this framework can be used to offload + memory copies to and from devices like qspi, ethernet + etc Drivers provide methods to access the DMA devices + buses that is used to transfer data to and from memory. + The uclass interface is defined in include/dma.h. + +endmenu # menu "DMA Support" diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index f95fe70..4ff22aa 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -5,6 +5,8 @@ # SPDX-License-Identifier: GPL-2.0+ # +obj-$(CONFIG_DM_DMA) += dma-uclass.o + obj-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o obj-$(CONFIG_APBH_DMA) += apbh_dma.o obj-$(CONFIG_FSL_DMA) += fsl_dma.o diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c new file mode 100644 index 0000000..1afcbaa4 --- /dev/null +++ b/drivers/dma/dma-uclass.c @@ -0,0 +1,63 @@ +/* + * Direct Memory Access U-Class driver + * + * (C) Copyright 2015 + * Texas Instruments Incorporated, <www.ti.com> + * + * Author: Mugunthan V N <mugunthanvnm@ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dma.h> +#include <dm.h> +#include <dm/uclass-internal.h> +#include <errno.h> + +DECLARE_GLOBAL_DATA_PTR; + +int dma_memcpy(void *dst, void *src, size_t len) +{ + struct udevice *dev; + const struct dma_ops *ops; + int ret; + + for (ret = uclass_find_first_device(UCLASS_DMA, &dev); dev && !ret; + ret = uclass_find_next_device(&dev)) { + struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + if (uc_priv->supported & SUPPORTS_MEM_TO_MEM) + break; + } + + if (!dev) { + printf("No DMA device found that supports mem to mem transfers\n"); + return -ENODEV; + } + + ops = device_get_ops(dev); + if (!ops->transfer) + return -ENOSYS; + + /* Invalidate the area, so no writeback into the RAM races with DMA */ + invalidate_dcache_range((unsigned long)dst, (unsigned long)dst + + roundup(len, ARCH_DMA_MINALIGN)); + + return ops->transfer(dev, DMA_MEM_TO_MEM, dst, src, len); +} + +int dma_post_bind(struct udevice *dev) +{ + struct udevice *devp; + uclass_get_device_by_of_offset(UCLASS_DMA, dev->of_offset, &devp); + return 0; +} + +UCLASS_DRIVER(dma) = { + .id = UCLASS_DMA, + .name = "dma", + .flags = DM_UC_FLAG_SEQ_ALIAS, + .per_device_auto_alloc_size = sizeof(struct dma_dev_priv), + .post_bind = dma_post_bind, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 27fa0b6..9f5fcae 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -30,6 +30,7 @@ enum uclass_id { UCLASS_CPU, /* CPU, typically part of an SoC */ UCLASS_CROS_EC, /* Chrome OS EC */ UCLASS_DISPLAY_PORT, /* Display port video */ + UCLASS_DMA, /* Direct Memory Access */ UCLASS_RAM, /* RAM controller */ UCLASS_ETH, /* Ethernet device */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */ diff --git a/include/dma.h b/include/dma.h new file mode 100644 index 0000000..d53e435 --- /dev/null +++ b/include/dma.h @@ -0,0 +1,64 @@ +/* + * (C) Copyright 2015 + * Texas Instruments Incorporated, <www.ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _DMA_H_ +#define _DMA_H_ + +/* + * enum dma_direction - dma transfer direction indicator + * @DMA_MEM_TO_MEM: Memcpy mode + * @DMA_MEM_TO_DEV: From Memory to Device + * @DMA_DEV_TO_MEM: From Device to Memory + * @DMA_DEV_TO_DEV: From Device to Device + */ +enum dma_direction { + DMA_MEM_TO_MEM, + DMA_MEM_TO_DEV, + DMA_DEV_TO_MEM, + DMA_DEV_TO_DEV, + DMA_TRANS_NONE, +}; + +#define SUPPORTS_MEM_TO_MEM BIT(0) +#define SUPPORTS_MEM_TO_DEV BIT(1) +#define SUPPORTS_DEV_TO_MEM BIT(2) +#define SUPPORTS_DEV_TO_DEV BIT(3) + +/* + * struct dma_ops - Driver model DMA operations + * + * The uclass interface is implemented by all DMA devices which use + * driver model. + */ +struct dma_ops { + /* + * Get the current timer count + * + * @dev: The DMA device + * @direction: direction of data transfer should be one from + enum dma_direction + * @dst: Destination pointer + * @src: Source pointer + * @len: Length of the data to be copied. + * @return: 0 if OK, -ve on error + */ + int (*transfer)(struct udevice *dev, int direction, void *dst, + void *src, size_t len); +}; + +/* + * struct dma_dev_priv - information about a device used by the uclass + * + * @supported: mode of transfers that DMA can support + */ +struct dma_dev_priv { + unsigned long supported; +}; + +int dma_memcpy(void *dst, void *src, size_t len); + +#endif /* _DMA_H_ */
Implement a DMA uclass so that the devices like ethernet, spi, mmc etc can offload the data transfers from/to the device and memory. Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> --- drivers/dma/Kconfig | 15 ++++++++++++ drivers/dma/Makefile | 2 ++ drivers/dma/dma-uclass.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/dma.h | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 145 insertions(+) create mode 100644 drivers/dma/dma-uclass.c create mode 100644 include/dma.h