All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support
@ 2018-02-12 16:38 Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 01/14] dma: add dma channels support and improve uclass Álvaro Fernández Rojas
                   ` (18 more replies)
  0 siblings, 19 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

In order to add bcm6348-enet support, dma-uclass must be extended to support
dma channels and rewordked to operate like the other dm uclass (clk, reset...).

This is an RFC, so please give you feedback on the things that I should
fix or rework.

Álvaro Fernández Rojas (14):
  dma: add dma channels support and improve uclass
  dma: add bcm6348-iudma support
  bmips: bcm6338: add bcm6348-iudma support
  bmips: bcm6348: add bcm6348-iudma support
  bmips: bcm6358: add bcm6348-iudma support
  phy: add support for internal phys
  net: add support for bcm6348-enet
  bmips: bcm6338: add support for bcm6348-enet
  bmips: enable f at st1704 enet support
  bmips: bcm6348: add support for bcm6348-enet
  bmips: enable ct-5361 enet support
  bmips: bcm6358: add support for bcm6348-enet
  bmips: enable hg556a enet support
  bmips: enable nb4-ser enet support

 arch/mips/dts/brcm,bcm6338.dtsi       |  29 ++
 arch/mips/dts/brcm,bcm6348.dtsi       |  42 +++
 arch/mips/dts/brcm,bcm6358.dtsi       |  46 +++
 arch/mips/dts/comtrend,ct-5361.dts    |  12 +
 arch/mips/dts/huawei,hg556a.dts       |  12 +
 arch/mips/dts/sagem,f at st1704.dts      |  12 +
 arch/mips/dts/sfr,nb4-ser.dts         |  24 ++
 configs/comtrend_ct5361_ram_defconfig |   8 +-
 configs/huawei_hg556a_ram_defconfig   |   8 +-
 configs/sagem_f at st1704_ram_defconfig  |   9 +-
 configs/sfr_nb4-ser_ram_defconfig     |   8 +-
 drivers/dma/Kconfig                   |   8 +
 drivers/dma/Makefile                  |   1 +
 drivers/dma/bcm6348-iudma.c           | 498 ++++++++++++++++++++++++++++++++
 drivers/dma/dma-uclass.c              | 212 +++++++++++---
 drivers/mtd/spi/sf-uclass.c           |  17 ++
 drivers/mtd/spi/spi_flash.c           |  11 +-
 drivers/net/Kconfig                   |   9 +
 drivers/net/Makefile                  |   1 +
 drivers/net/bcm6348-eth.c             | 517 ++++++++++++++++++++++++++++++++++
 include/configs/bmips_common.h        |   5 +-
 include/dma-uclass.h                  | 110 ++++++++
 include/dma.h                         | 226 +++++++++++----
 include/dt-bindings/dma/bcm6338-dma.h |  15 +
 include/dt-bindings/dma/bcm6348-dma.h |  17 ++
 include/dt-bindings/dma/bcm6358-dma.h |  17 ++
 include/phy.h                         |   2 +
 include/spi_flash.h                   |   3 +
 28 files changed, 1780 insertions(+), 99 deletions(-)
 create mode 100644 drivers/dma/bcm6348-iudma.c
 create mode 100644 drivers/net/bcm6348-eth.c
 create mode 100644 include/dma-uclass.h
 create mode 100644 include/dt-bindings/dma/bcm6338-dma.h
 create mode 100644 include/dt-bindings/dma/bcm6348-dma.h
 create mode 100644 include/dt-bindings/dma/bcm6358-dma.h

-- 
2.11.0

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 01/14] dma: add dma channels support and improve uclass
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-20  8:24   ` Vignesh R
  2018-02-12 16:38 ` [U-Boot] [RFC 02/14] dma: add bcm6348-iudma support Álvaro Fernández Rojas
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 drivers/dma/dma-uclass.c    | 212 ++++++++++++++++++++++++++++++++++-------
 drivers/mtd/spi/sf-uclass.c |  17 ++++
 drivers/mtd/spi/spi_flash.c |  11 ++-
 include/dma-uclass.h        | 110 +++++++++++++++++++++
 include/dma.h               | 226 +++++++++++++++++++++++++++++++++-----------
 include/spi_flash.h         |   3 +
 6 files changed, 485 insertions(+), 94 deletions(-)
 create mode 100644 include/dma-uclass.h

diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
index 3d0ce22fbc..7d04d98493 100644
--- a/drivers/dma/dma-uclass.c
+++ b/drivers/dma/dma-uclass.c
@@ -1,59 +1,176 @@
 /*
- * Direct Memory Access U-Class driver
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated, <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
  *
- * (C) Copyright 2015
- *     Texas Instruments Incorporated, <www.ti.com>
- *
- * Author: Mugunthan V N <mugunthanvnm@ti.com>
- *
- * SPDX-License-Identifier:     GPL-2.0+
+ * SPDX-License-Identifier:	GPL-2.0+
  */
 
 #include <common.h>
-#include <dma.h>
 #include <dm.h>
-#include <dm/uclass-internal.h>
-#include <dm/device-internal.h>
+#include <dma.h>
+#include <dma-uclass.h>
+#include <dt-structs.h>
 #include <errno.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-int dma_get_device(u32 transfer_type, struct udevice **devp)
+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)
 {
-	struct udevice *dev;
 	int ret;
 
-	for (ret = uclass_first_device(UCLASS_DMA, &dev); dev && !ret;
-	     ret = uclass_next_device(&dev)) {
-		struct dma_dev_priv *uc_priv;
+	if (index != 0)
+		return -ENOSYS;
+	ret = uclass_get_device(UCLASS_DMA, 0, &dma->dev);
+	if (ret)
+		return ret;
+	dma->id = cells[0].id;
 
-		uc_priv = dev_get_uclass_priv(dev);
-		if (uc_priv->supported & transfer_type)
-			break;
-	}
+	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 (!dev) {
-		pr_err("No DMA device found that supports %x type\n",
-		      transfer_type);
-		return -EPROTONOSUPPORT;
+	if (args->args_count > 1) {
+		pr_err("Invaild args_count: %d\n", args->args_count);
+		return -EINVAL;
 	}
 
-	*devp = dev;
+	if (args->args_count)
+		dma->id = args->args[0];
+	else
+		dma->id = 0;
 
-	return ret;
+	return 0;
 }
 
-int dma_memcpy(void *dst, void *src, size_t len)
+int dma_get_by_index(struct udevice *dev, int index, struct dma *dma)
 {
-	struct udevice *dev;
-	const struct dma_ops *ops;
 	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);
 
-	ret = dma_get_device(DMA_SUPPORTS_MEM_TO_MEM, &dev);
-	if (ret < 0)
+	assert(dma);
+	ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
+					     "dmas", "#dma-cells", 0, index,
+					     &args);
+	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);
+	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_memcpy(struct dma *dma, void *dst, void *src, size_t len)
+{
+	struct dma_ops *ops = dma_dev_ops(dma->dev);
+
+	debug("%s(dma=%p)\n", __func__, dma);
 
-	ops = device_get_ops(dev);
 	if (!ops->transfer)
 		return -ENOSYS;
 
@@ -61,12 +178,35 @@ int dma_memcpy(void *dst, void *src, size_t len)
 	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);
+	return ops->transfer(dma, DMA_MEM_TO_MEM, dst, src, len);
+}
+
+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);
 }
 
 UCLASS_DRIVER(dma) = {
-	.id		= UCLASS_DMA,
-	.name		= "dma",
-	.flags		= DM_UC_FLAG_SEQ_ALIAS,
-	.per_device_auto_alloc_size = sizeof(struct dma_dev_priv),
+	.id = UCLASS_DMA,
+	.name = "dma",
+	.flags = DM_UC_FLAG_SEQ_ALIAS,
 };
diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c
index 83876485fe..992dead1a2 100644
--- a/drivers/mtd/spi/sf-uclass.c
+++ b/drivers/mtd/spi/sf-uclass.c
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <dm.h>
+#include <dma.h>
 #include <spi.h>
 #include <spi_flash.h>
 #include <dm/device-internal.h>
@@ -72,6 +73,22 @@ int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
 		return ret;
 
 	*devp = slave->dev;
+
+#ifdef CONFIG_DMA
+	if (fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(*devp),
+				  "dmas") > 0) {
+		struct spi_flash *priv = dev_get_uclass_priv(*devp);
+
+		priv->dma = calloc(1, sizeof(struct dma));
+		if (!priv->dma)
+			return -ENOMEM;
+
+		ret = dma_get_by_index(*devp, 0, priv->dma);
+		if (ret)
+			return -EINVAL;
+	}
+#endif
+
 	return 0;
 }
 
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 294d9f9d79..8b1c6a27de 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -458,10 +458,6 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
  */
 void __weak spi_flash_copy_mmap(void *data, void *offset, size_t len)
 {
-#ifdef CONFIG_DMA
-	if (!dma_memcpy(data, offset, len))
-		return;
-#endif
 	memcpy(data, offset, len);
 }
 
@@ -482,7 +478,12 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 			return ret;
 		}
 		spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP);
-		spi_flash_copy_mmap(data, flash->memory_map + offset, len);
+		if (flash->dma)
+			dma_memcpy(flash->dma, data,
+				   flash->memory_map + offset, len);
+		else
+			spi_flash_copy_mmap(data, flash->memory_map + offset,
+					    len);
 		spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP_END);
 		spi_release_bus(spi);
 		return 0;
diff --git a/include/dma-uclass.h b/include/dma-uclass.h
new file mode 100644
index 0000000000..0315e54441
--- /dev/null
+++ b/include/dma-uclass.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated, <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DMA_UCLASS_H
+#define _DMA_UCLASS_H
+
+/* See dma.h for background documentation. */
+
+#include <dma.h>
+#include <fdtdec.h>
+
+/**
+ * struct dma_ops - The functions that a DMA driver must implement.
+ */
+struct dma_ops {
+	/**
+	 * 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);
+	/**
+	 * request - Request a translated DMA.
+	 *
+	 * The DMA core calls this function as the second step in
+	 * implementing a client's dma_get_by_*() call, following a successful
+	 * xxx_xlate() call, or as the only step in implementing a client's
+	 * dma_request() call.
+	 *
+	 * @dma: The DMA struct to request; this has been filled in by
+	 *   a previoux xxx_xlate() function call, or by the caller of
+	 *   dma_request().
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*request)(struct dma *dma);
+	/**
+	 * free - Free a previously requested dma.
+	 *
+	 * This is the implementation of the client dma_free() API.
+	 *
+	 * @dma: The DMA to free.
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*free)(struct dma *dma);
+	/**
+	 * enable() - Enable a DMA Channel.
+	 *
+	 * @dma: The DMA Channel to manipulate.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*enable)(struct dma *dma);
+	/**
+	 * disable() - Disable a DMA Channel.
+	 *
+	 * @dma: The DMA Channel to manipulate.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*disable)(struct dma *dma);
+	/**
+	 * transfer() - Issue a DMA transfer.
+	 *
+	 * @dma: The DMA Channel to manipulate.
+	 * @dir: The direction of data transfer.
+	 * @dst: The destination pointer.
+	 * @src: The source pointer.
+	 * @len: Length of the data to be copied.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*transfer)(struct dma *dma, enum dma_transfer_direction dir,
+			void *dst, void *src, size_t len);
+	/**
+	 * 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 copied.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*send)(struct dma *dma, void *src, size_t len);
+
+};
+
+#endif /* _DMA_UCLASS_H */
diff --git a/include/dma.h b/include/dma.h
index 71fa77f2ea..3632e3256d 100644
--- a/include/dma.h
+++ b/include/dma.h
@@ -1,86 +1,206 @@
 /*
- * (C) Copyright 2015
- *     Texas Instruments Incorporated, <www.ti.com>
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated, <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
  *
- * SPDX-License-Identifier:     GPL-2.0+
+ * SPDX-License-Identifier:	GPL-2.0+
  */
 
 #ifndef _DMA_H_
 #define _DMA_H_
 
+#include <linux/errno.h>
+#include <linux/types.h>
+
 /*
- * enum dma_direction - dma transfer direction indicator
+ * enum dma_transfer_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 {
+enum dma_transfer_direction {
 	DMA_MEM_TO_MEM,
 	DMA_MEM_TO_DEV,
 	DMA_DEV_TO_MEM,
 	DMA_DEV_TO_DEV,
 };
 
-#define DMA_SUPPORTS_MEM_TO_MEM	BIT(0)
-#define DMA_SUPPORTS_MEM_TO_DEV	BIT(1)
-#define DMA_SUPPORTS_DEV_TO_MEM	BIT(2)
-#define DMA_SUPPORTS_DEV_TO_DEV	BIT(3)
+/**
+ * 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 provider. A provider will
+ * often implement multiple separate DMAs, since the hardware it manages
+ * often has this capability. dma_uclass.h describes the interface which
+ * DMA providers must implement.
+ * 
+ * DMA consumers/clients are the HW modules driven by the DMA channels. This
+ * header file describes the API used by drivers for those HW modules.
+ */
 
-/*
- * struct dma_ops - Driver model DMA operations
+struct udevice;
+
+/**
+ * struct dma - A handle to (allowing control of) a single DMA.
+ *
+ * Clients provide storage for DMA handles. The content of the structure is
+ * managed solely by the DMA API and DMA drivers. A DMA struct is
+ * initialized by "get"ing the DMA struct. The DMA struct is passed to all
+ * other DMA APIs to identify which DMA channel to operate upon.
  *
- * The uclass interface is implemented by all DMA devices which use
- * driver model.
+ * @dev: The device which implements the DMA channel.
+ * @id: The DMA channel ID within the provider.
+ *
+ * Currently, the DMA API assumes that a single integer ID is enough to
+ * identify and configure any DMA channel for any DMA provider. If this
+ * assumption becomes invalid in the future, the struct could be expanded to
+ * either (a) add more fields to allow DMA providers to store additional
+ * information, or (b) replace the id field with an opaque pointer, which the
+ * provider would dynamically allocated during its .of_xlate op, and process
+ * during is .request op. This may require the addition of an extra op to clean
+ * up the allocation.
  */
-struct dma_ops {
+struct dma {
+	struct udevice *dev;
 	/*
-	 * 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
+	 * Written by of_xlate. We assume a single id is enough for now. In the
+	 * future, we might add more fields here.
 	 */
-	int (*transfer)(struct udevice *dev, int direction, void *dst,
-			void *src, size_t len);
+	unsigned long id;
 };
 
-/*
- * struct dma_dev_priv - information about a device used by the uclass
+#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DMA)
+struct phandle_2_cell;
+int dma_get_by_index_platdata(struct udevice *dev, int index,
+			      struct phandle_2_cell *cells, struct dma *dma);
+
+/**
+ * dma_get_by_index - Get/request a DMA by integer index.
+ *
+ * This looks up and requests a DMA. The index is relative to the client
+ * device; each device is assumed to have n DMAs associated with it somehow,
+ * and this function finds and requests one of them. The mapping of client
+ * device DMA indices to provider DMAs may be via device-tree properties,
+ * board-provided mapping tables, or some other mechanism.
  *
- * @supported: mode of transfers that DMA can support, should be
- *	       one/multiple of DMA_SUPPORTS_*
+ * @dev:	The client device.
+ * @index:	The index of the DMA to request, within the client's list of
+ *		DMA channels.
+ * @dma:	A pointer to a DMA struct to initialize.
+ * @return 0 if OK, or a negative error code.
  */
-struct dma_dev_priv {
-	u32 supported;
-};
+int dma_get_by_index(struct udevice *dev, int index, struct dma *dma);
 
-/*
- * dma_get_device - get a DMA device which supports transfer
- * type of transfer_type
- *
- * @transfer_type - transfer type should be one/multiple of
- *		    DMA_SUPPORTS_*
- * @devp - udevice pointer to return the found device
- * @return - will return on success and devp will hold the
- *	     pointer to the device
+/**
+ * dma_get_by_name - Get/request a DMA by name.
+ *
+ * This looks up and requests a DMA. The name is relative to the client
+ * device; each device is assumed to have n DMAs associated with it somehow,
+ * and this function finds and requests one of them. The mapping of client
+ * device DMA names to provider DMAs may be via device-tree properties,
+ * board-provided mapping tables, or some other mechanism.
+ *
+ * @dev:	The client device.
+ * @name:	The name of the DMA to request, within the client's list of
+ *		DMA channels.
+ * @dma:	A pointer to a DMA struct to initialize.
+ * @return 0 if OK, or a negative error code.
  */
-int dma_get_device(u32 transfer_type, struct udevice **devp);
+int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma);
+#else
+static inline int dma_get_by_index(struct udevice *dev, int index,
+				   struct dma *dma)
+{
+	return -ENOSYS;
+}
 
-/*
- * dma_memcpy - try to use DMA to do a mem copy which will be
- *		much faster than CPU mem copy
- *
- * @dst - destination pointer
- * @src - souce pointer
- * @len - data length to be copied
- * @return - on successful transfer returns no of bytes
-	     transferred and on failure return error code.
+static inline int dma_get_by_name(struct udevice *dev, const char *name,
+			   struct dma *dma)
+{
+	return -ENOSYS;
+}
+#endif
+
+/**
+ * dma_request - Request a DMA by provider-specific ID.
+ *
+ * This requests a DMA using a provider-specific ID. Generally, this function
+ * should not be used, since dma_get_by_index/name() provide an interface that
+ * better separates clients from intimate knowledge of DMA providers.
+ * However, this function may be useful in core SoC-specific code.
+ *
+ * @dev: The DMA provider device.
+ * @dma: A pointer to a DMA struct to initialize. The caller must
+ *	 have already initialized any field in this struct which the
+ *	 DMA provider uses to identify the DMA channel.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_request(struct udevice *dev, struct dma *dma);
+
+/**
+ * dma_free - Free a previously requested DMA.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_free(struct dma *dma);
+
+/**
+ * dma_enable() - Enable (turn on) a DMA channel.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return zero on success, or -ve error code.
+ */
+int dma_enable(struct dma *dma);
+
+/**
+ * dma_disable() - Disable (turn off) a DMA channel.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return zero on success, or -ve error code.
+ */
+int dma_disable(struct dma *dma);
+
+/**
+ * dma_memcpy() - Try to use DMA to do a mem copy which will be much faster
+ *		  than CPU mem copy.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @dst: The destination pointer.
+ * @src: The source pointer.
+ * @len: Length of the data to be copied.
+ * @return zero on success, or -ve error code.
+ */
+int dma_memcpy(struct dma *dma, void *dst, void *src, size_t len);
+
+/**
+ * dma_receive() - Receive a DMA transfer.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @dst: The destination pointer.
+ * @return zero on success, or -ve error code.
+ */
+int dma_receive(struct dma *dma, void **dst);
+
+/**
+ * dma_send() - Send a DMA transfer.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @src: The source pointer.
+ * @len: Length of the data to be copied.
+ * @return zero on success, or -ve error code.
  */
-int dma_memcpy(void *dst, void *src, size_t len);
+int dma_send(struct dma *dma, void *src, size_t len);
 
-#endif	/* _DMA_H_ */
+#endif /* _DMA_H_ */
diff --git a/include/spi_flash.h b/include/spi_flash.h
index f3c4e83424..f31e8b8145 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -65,6 +65,9 @@ struct spi_flash {
 #ifdef CONFIG_DM_SPI_FLASH
 	struct udevice *dev;
 #endif
+#ifdef CONFIG_DMA
+	struct dma *dma;
+#endif
 	const char *name;
 	u8 dual_flash;
 	u8 shift;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 02/14] dma: add bcm6348-iudma support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 01/14] dma: add dma channels support and improve uclass Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 03/14] bmips: bcm6338: " Álvaro Fernández Rojas
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 drivers/dma/Kconfig         |   8 +
 drivers/dma/Makefile        |   1 +
 drivers/dma/bcm6348-iudma.c | 498 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 507 insertions(+)
 create mode 100644 drivers/dma/bcm6348-iudma.c

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 1b92c7789d..f58323f6c0 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -12,6 +12,14 @@ config DMA
 	  buses that is used to transfer data to and from memory.
 	  The uclass interface is defined in include/dma.h.
 
+config BCM6348_IUDMA
+	bool "BCM6348 IUDMA driver"
+	depends on ARCH_BMIPS
+	help
+	  Enable the BCM6348 IUDMA driver.
+	  This driver support data transfer from devices to
+	  memory and from memory to devices.
+
 config TI_EDMA3
 	bool "TI EDMA3 driver"
 	help
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 39b78b2a3d..b2b4147349 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_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_BCM6348_IUDMA) += bcm6348-iudma.o
 obj-$(CONFIG_FSL_DMA) += fsl_dma.o
 obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
 obj-$(CONFIG_TI_EDMA3) += ti-edma3.o
diff --git a/drivers/dma/bcm6348-iudma.c b/drivers/dma/bcm6348-iudma.c
new file mode 100644
index 0000000000..22d81cc990
--- /dev/null
+++ b/drivers/dma/bcm6348-iudma.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/dma/bcm63xx-iudma.c:
+ *	Copyright (C) 2015 Simon Arlott <simon@fire.lp0.eu>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
+ *	Copyright (C) 2000-2010 Broadcom Corporation
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/bcmdrivers/opensource/net/enet/impl4/bcmenet.c:
+ *	Copyright (C) 2010 Broadcom Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma-uclass.h>
+#include <memalign.h>
+#include <net.h>
+#include <reset.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ALIGN_END_ADDR(type, ptr, size)	\
+	((unsigned long)(ptr) + roundup((size) * sizeof(type), \
+	 ARCH_DMA_MINALIGN))
+
+#define DMA_MAX_BURST_LENGTH	16
+
+/* DMA Channels */
+#define DMA_CHAN_FLOWC(x)		((x) >> 1)
+#define DMA_CHAN_FLOWC_MAX		8
+#define DMA_CHAN_MAX			16
+#define DMA_CHAN_SIZE			0x10
+#define DMA_CHAN_TOUT			500
+
+/* DMA Global Configuration register */
+#define DMA_CFG_REG			0x00
+#define DMA_CFG_ENABLE_SHIFT		0
+#define DMA_CFG_ENABLE_MASK		(1 << DMA_CFG_ENABLE_SHIFT)
+#define DMA_CFG_FLOWC_ENABLE(x)		BIT(DMA_CHAN_FLOWC(x) + 1)
+#define DMA_CFG_NCHANS_SHIFT		24
+#define DMA_CFG_NCHANS_MASK		(0xf << DMA_CFG_NCHANS_SHIFT)
+
+/* DMA Global Flow Control Threshold registers */
+#define DMA_FLOWC_THR_LO_REG(x)		(0x04 + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_THR_LO_SHIFT		0
+#define DMA_FLOWC_THR_LO_MASK		(5 << DMA_FLOWC_THR_LO_SHIFT)
+
+#define DMA_FLOWC_THR_HI_REG(x)		(0x08 + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_THR_HI_SHIFT		0
+#define DMA_FLOWC_THR_HI_MASK		(10 << DMA_FLOWC_THR_HI_SHIFT)
+
+/* DMA Global Flow Control Buffer Allocation registers */
+#define DMA_FLOWC_ALLOC_REG(x)		(0x0c + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_ALLOC_FORCE_SHIFT	31
+#define DMA_FLOWC_ALLOC_FORCE_MASK	(1 << DMA_FLOWC_ALLOC_FORCE_SHIFT)
+
+/* DMA Global Reset register */
+#define DMA_RST_REG			0x34
+#define DMA_RST_CHAN_SHIFT		0
+#define DMA_RST_CHAN_MASK(x)		(1 << x)
+
+/* DMA Channel Configuration register */
+#define DMAC_CFG_REG(x)			(DMA_CHAN_SIZE * (x) + 0x00)
+#define DMAC_CFG_ENABLE_SHIFT		0
+#define DMAC_CFG_ENABLE_MASK		(1 << DMAC_CFG_ENABLE_SHIFT)
+#define DMAC_CFG_PKT_HALT_SHIFT		1
+#define DMAC_CFG_PKT_HALT_MASK		(1 << DMAC_CFG_PKT_HALT_SHIFT)
+#define DMAC_CFG_BRST_HALT_SHIFT	2
+#define DMAC_CFG_BRST_HALT_MASK		(1 << DMAC_CFG_BRST_HALT_SHIFT)
+
+/* DMA Channel Interrupts registers */
+#define DMAC_IR_ST_REG(x)		(DMA_CHAN_SIZE * (x) + 0x04)
+#define DMAC_IR_EN_REG(x)		(DMA_CHAN_SIZE * (x) + 0x08)
+
+#define DMAC_IR_DONE_SHIFT		2
+#define DMAC_IR_DONE_MASK		(1 << DMAC_IR_DONE_SHIFT)
+
+/* DMA Channel Max Burst Length register */
+#define DMAC_BURST_REG(x)		(DMA_CHAN_SIZE * (x) + 0x0c)
+#define DMAC_BURST_MAX_SHIFT		0
+#define DMAC_BURST_MAX_MASK		(16 << DMAC_BURST_MAX_SHIFT)
+
+/* DMA SRAM Descriptor Ring Start register */
+#define DMAS_RSTART_REG(x)		(DMA_CHAN_SIZE * (x) + 0x00)
+
+/* DMA SRAM State/Bytes done/ring offset register */
+#define DMAS_STATE_DATA_REG(x)		(DMA_CHAN_SIZE * (x) + 0x04)
+
+/* DMA SRAM Buffer Descriptor status and length register */
+#define DMAS_DESC_LEN_STATUS_REG(x)	(DMA_CHAN_SIZE * (x) + 0x08)
+
+/* DMA SRAM Buffer Descriptor status and length register */
+#define DMAS_DESC_BASE_BUFPTR_REG(x)	(DMA_CHAN_SIZE * (x) + 0x0c)
+
+struct bcm6348_dma_desc {
+	uint16_t length;
+
+	uint16_t status;
+#define DMAD_ST_CRC_SHIFT	8
+#define DMAD_ST_CRC_MASK	(1 << DMAD_ST_CRC_SHIFT)
+#define DMAD_ST_WRAP_SHIFT	12
+#define DMAD_ST_WRAP_MASK	(1 << DMAD_ST_WRAP_SHIFT)
+#define DMAD_ST_SOP_SHIFT	13
+#define DMAD_ST_SOP_MASK	(1 << DMAD_ST_SOP_SHIFT)
+#define DMAD_ST_EOP_SHIFT	14
+#define DMAD_ST_EOP_MASK	(1 << DMAD_ST_EOP_SHIFT)
+#define DMAD_ST_OWN_SHIFT	15
+#define DMAD_ST_OWN_MASK	(1 << DMAD_ST_OWN_SHIFT)
+
+	uint32_t address;
+} __attribute__((aligned(1)));
+
+struct bcm6348_chan_priv {
+	void __iomem *dma_ring;
+	uint8_t dma_ring_size;
+	uint8_t desc_id;
+};
+
+struct bcm6348_iudma_priv {
+	void __iomem *base;
+	void __iomem *chan;
+	void __iomem *sram;
+	struct bcm6348_chan_priv **ch_priv;
+	uint8_t n_channels;
+};
+
+static bool bcm6348_iudma_chan_is_rx(uint8_t ch)
+{
+	return !(ch & 1);
+}
+
+static void bcm6348_iudma_chan_stop(struct bcm6348_iudma_priv *priv,
+				    uint8_t ch)
+{
+	unsigned int timeout = DMA_CHAN_TOUT;
+
+	/* disable dma channel interrupts */
+	writel_be(0, priv->chan + DMAC_IR_EN_REG(ch));
+
+	do {
+		uint32_t cfg, halt;
+
+		if (timeout > DMA_CHAN_TOUT / 2)
+			halt = DMAC_CFG_PKT_HALT_MASK;
+		else
+			halt = DMAC_CFG_BRST_HALT_MASK;
+
+		/* try to stop dma channel */
+		writel_be(halt, priv->chan + DMAC_CFG_REG(ch));
+		mb();
+
+		/* check if channel was stopped */
+		cfg = readl_be(priv->chan + DMAC_CFG_REG(ch));
+		if (!(cfg & DMAC_CFG_ENABLE_MASK))
+			break;
+
+		udelay(1);
+	} while (--timeout);
+
+	if (!timeout)
+		pr_err("unable to stop channel %u\n", ch);
+
+	/* reset dma channel */
+	setbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
+	clrbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
+}
+
+static int bcm6348_iudma_disable(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+
+	bcm6348_iudma_chan_stop(priv, dma->id);
+
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		writel_be(DMA_FLOWC_ALLOC_FORCE_MASK,
+			  DMA_FLOWC_ALLOC_REG(dma->id));
+
+	return 0;
+}
+
+static int bcm6348_iudma_enable(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	uint8_t i;
+
+	/* init dma rings */
+	dma_desc = ch_priv->dma_ring;
+	for (i = 0; i < ch_priv->dma_ring_size; i++) {
+		if (bcm6348_iudma_chan_is_rx(dma->id)) {
+			dma_desc->status = DMAD_ST_OWN_MASK;
+			dma_desc->length = PKTSIZE_ALIGN;
+			dma_desc->address = virt_to_phys(net_rx_packets[i]);
+		} else {
+			dma_desc->status = 0;
+			dma_desc->length = 0;
+			dma_desc->address = 0;
+		}
+
+		if (i == ch_priv->dma_ring_size - 1)
+			dma_desc->status |= DMAD_ST_WRAP_MASK;
+
+		if (bcm6348_iudma_chan_is_rx(dma->id))
+			writel_be(1,
+				  priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
+
+		dma_desc++;
+	}
+
+	/* init to first descriptor */
+	ch_priv->desc_id = 0;
+
+	/* force cache writeback */
+	flush_dcache_range((ulong)ch_priv->dma_ring,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, ch_priv->dma_ring,
+			       ch_priv->dma_ring_size));
+
+	/* clear sram */
+	writel_be(0, priv->sram + DMAS_STATE_DATA_REG(dma->id));
+	writel_be(0, priv->sram + DMAS_DESC_LEN_STATUS_REG(dma->id));
+	writel_be(0, priv->sram + DMAS_DESC_BASE_BUFPTR_REG(dma->id));
+
+	/* set dma ring start */
+	writel_be(virt_to_phys(ch_priv->dma_ring),
+		  priv->sram + DMAS_RSTART_REG(dma->id));
+
+	/* set flow control */
+	if (bcm6348_iudma_chan_is_rx(dma->id)) {
+		setbits_be32(priv->base + DMA_CFG_REG,
+			     DMA_CFG_FLOWC_ENABLE(dma->id));
+		writel_be(DMA_FLOWC_THR_LO_MASK,
+			  priv->base + DMA_FLOWC_THR_LO_REG(dma->id));
+		writel_be(DMA_FLOWC_THR_HI_MASK,
+			  priv->base + DMA_FLOWC_THR_HI_REG(dma->id));
+	}
+
+	/* set dma max burst */
+	writel_be(DMA_MAX_BURST_LENGTH, priv->chan + DMAC_BURST_REG(dma->id));
+
+	/* clear interrupts */
+	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_ST_REG(dma->id));
+	writel_be(0, priv->chan + DMAC_IR_EN_REG(dma->id));
+
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	return 0;
+}
+
+static int bcm6348_iudma_request(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv;
+
+	/* check if channel is valid */
+	if (dma->id >= priv->n_channels)
+		return -ENODEV;
+
+	/* alloc channel private data */
+	priv->ch_priv[dma->id] = calloc(1, sizeof(struct bcm6348_chan_priv));
+	if (!priv->ch_priv[dma->id])
+		return -ENOMEM;
+	ch_priv = priv->ch_priv[dma->id];
+
+	/* alloc dma ring */
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		ch_priv->dma_ring_size = PKTBUFSRX;
+	else
+		ch_priv->dma_ring_size = 1;
+	ch_priv->dma_ring =
+		malloc_cache_aligned(sizeof(struct bcm6348_dma_desc) *
+				     ch_priv->dma_ring_size);
+	if (!ch_priv->dma_ring)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int bcm6348_iudma_receive(struct dma *dma, void **dst)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	void __iomem *dma_buff;
+	uint16_t status;
+	int ret;
+
+	/* get dma ring descriptor address */
+	dma_desc = ch_priv->dma_ring;
+	dma_desc += ch_priv->desc_id;
+
+	/* invalidate cache data */
+	invalidate_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* check dma own */
+	if (dma_desc->status & DMAD_ST_OWN_MASK)
+		return 0;
+
+	/* check dma end */
+	if (!(dma_desc->status & DMAD_ST_EOP_MASK))
+		return -EINVAL;
+
+	/* get dma buff descriptor address */
+	dma_buff = phys_to_virt(dma_desc->address);
+
+	/* invalidate cache data */
+	invalidate_dcache_range((ulong)dma_buff,
+				(ulong)(dma_buff + PKTSIZE_ALIGN));
+
+	/* get dma data */
+	*dst = dma_buff;
+	ret = dma_desc->length;
+
+	/* reinit dma descriptor */
+	status = dma_desc->status & DMAD_ST_WRAP_MASK;
+	status |= DMAD_ST_OWN_MASK;
+
+	dma_desc->length = PKTSIZE_ALIGN;
+	dma_desc->status = status;
+
+	/* flush cache */
+	flush_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* set flow control buffer alloc */
+	writel_be(1, priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
+
+	/* enable dma */
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	/* set interrupt */
+	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_EN_REG(dma->id));
+
+	/* increment dma descriptor */
+	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->dma_ring_size;
+
+	return ret - 4;
+}
+
+static int bcm6348_iudma_send(struct dma *dma, void *src, size_t len)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	uint16_t val;
+
+	/* get dma ring descriptor address */
+	dma_desc = ch_priv->dma_ring;
+	dma_desc += ch_priv->desc_id;
+
+	dma_desc->address = virt_to_phys(src);
+
+	/* config dma descriptor */
+	val = (DMAD_ST_OWN_MASK |
+	       DMAD_ST_EOP_MASK |
+	       DMAD_ST_CRC_MASK |
+	       DMAD_ST_SOP_MASK);
+	if (ch_priv->desc_id == ch_priv->dma_ring_size - 1)
+		val |= DMAD_ST_WRAP_MASK;
+
+	dma_desc->length = len;
+	dma_desc->status = val;
+
+	/* flush cache */
+	flush_dcache_range((ulong)src, (ulong)src + PKTSIZE_ALIGN);
+
+	/* flush cache */
+	flush_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* enable dma */
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	/* set interrupt */
+	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_EN_REG(dma->id));
+
+	/* poll dma status */
+	do {
+		/* invalidate cache */
+		invalidate_dcache_range((ulong)dma_desc,
+			ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+		if (!(dma_desc->status & DMAD_ST_OWN_MASK))
+			break;
+	} while(1);
+
+	/* increment dma descriptor */
+	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->dma_ring_size;
+
+	return 0;
+}
+
+static const struct dma_ops bcm6348_iudma_ops = {
+	.disable = bcm6348_iudma_disable,
+	.enable = bcm6348_iudma_enable,
+	.request = bcm6348_iudma_request,
+	.receive = bcm6348_iudma_receive,
+	.send = bcm6348_iudma_send,
+};
+
+static const struct udevice_id bcm6348_iudma_ids[] = {
+	{ .compatible = "brcm,bcm6348-iudma", },
+	{ /* sentinel */ }
+};
+
+static int bcm6348_iudma_probe(struct udevice *dev)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+	uint8_t ch;
+	int i;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+		if (clk_enable(&clk))
+			pr_err("failed to enable clock %d\n", i);
+		clk_free(&clk);
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+		if (reset_deassert(&reset))
+			pr_err("failed to deassert reset %d\n", i);
+		reset_free(&reset);
+	}
+
+	/* dma global base address */
+	addr = devfdt_get_addr_name(dev, "dma");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->base = ioremap(addr, 0);
+
+	/* dma channels base address */
+	addr = devfdt_get_addr_name(dev, "dma-channels");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->chan = ioremap(addr, 0);
+
+	/* dma sram base address */
+	addr = devfdt_get_addr_name(dev, "dma-sram");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->sram = ioremap(addr, 0);
+
+	/* disable dma controller */
+	clrbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
+
+	/* get number of channels */
+	priv->n_channels = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+					   "dma-channels", 8);
+	if (priv->n_channels > DMA_CHAN_MAX)
+		return -EINVAL;
+
+	/* alloc channel private data pointers */
+	priv->ch_priv = calloc(priv->n_channels,
+			       sizeof(struct bcm6348_chan_priv*));
+	if (!priv->ch_priv)
+		return -ENOMEM;
+
+	/* stop dma channels */
+	for (ch = 0; ch < priv->n_channels; ch++)
+		bcm6348_iudma_chan_stop(priv, ch);
+
+	/* enable dma controller */
+	setbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_iudma) = {
+	.name = "bcm6348_iudma",
+	.id = UCLASS_DMA,
+	.of_match = bcm6348_iudma_ids,
+	.ops = &bcm6348_iudma_ops,
+	.priv_auto_alloc_size = sizeof(struct bcm6348_iudma_priv),
+	.probe = bcm6348_iudma_probe,
+};
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 03/14] bmips: bcm6338: add bcm6348-iudma support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 01/14] dma: add dma channels support and improve uclass Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 02/14] dma: add bcm6348-iudma support Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 04/14] bmips: bcm6348: " Álvaro Fernández Rojas
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 arch/mips/dts/brcm,bcm6338.dtsi       | 14 ++++++++++++++
 include/dt-bindings/dma/bcm6338-dma.h | 15 +++++++++++++++
 2 files changed, 29 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6338-dma.h

diff --git a/arch/mips/dts/brcm,bcm6338.dtsi b/arch/mips/dts/brcm,bcm6338.dtsi
index 0cab44cb8d..4125f71d9f 100644
--- a/arch/mips/dts/brcm,bcm6338.dtsi
+++ b/arch/mips/dts/brcm,bcm6338.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6338-clock.h>
+#include <dt-bindings/dma/bcm6338-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6338-reset.h>
 #include "skeleton.dtsi"
@@ -131,5 +132,18 @@
 			reg = <0xfffe3100 0x38>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller at fffe2400 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe2400 0x1c>,
+			      <0xfffe2500 0x60>,
+			      <0xfffe2600 0x60>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <6>;
+			resets = <&periph_rst BCM6338_RST_DMAMEM>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6338-dma.h b/include/dt-bindings/dma/bcm6338-dma.h
new file mode 100644
index 0000000000..5dd66239b4
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6338-dma.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6338_H
+#define __DT_BINDINGS_DMA_BCM6338_H
+
+#define BCM6338_DMA_ENET_RX	0
+#define BCM6338_DMA_ENET_TX	1
+
+#endif /* __DT_BINDINGS_DMA_BCM6338_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 04/14] bmips: bcm6348: add bcm6348-iudma support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (2 preceding siblings ...)
  2018-02-12 16:38 ` [U-Boot] [RFC 03/14] bmips: bcm6338: " Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 05/14] bmips: bcm6358: " Álvaro Fernández Rojas
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 arch/mips/dts/brcm,bcm6348.dtsi       | 16 ++++++++++++++++
 include/dt-bindings/dma/bcm6348-dma.h | 17 +++++++++++++++++
 2 files changed, 33 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6348-dma.h

diff --git a/arch/mips/dts/brcm,bcm6348.dtsi b/arch/mips/dts/brcm,bcm6348.dtsi
index 92fb91afc1..d774c59665 100644
--- a/arch/mips/dts/brcm,bcm6348.dtsi
+++ b/arch/mips/dts/brcm,bcm6348.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6348-clock.h>
+#include <dt-bindings/dma/bcm6348-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6348-reset.h>
 #include "skeleton.dtsi"
@@ -160,5 +161,20 @@
 			reg = <0xfffe2300 0x38>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller at fffe7000 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe7000 0x1c>,
+			      <0xfffe7100 0x40>,
+			      <0xfffe7200 0x40>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <4>;
+			clocks = <&periph_clk BCM6348_CLK_ENET>;
+			resets = <&periph_rst BCM6348_RST_ENET>,
+				 <&periph_rst BCM6348_RST_DMAMEM>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6348-dma.h b/include/dt-bindings/dma/bcm6348-dma.h
new file mode 100644
index 0000000000..a1d3a6456d
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6348-dma.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6348_H
+#define __DT_BINDINGS_DMA_BCM6348_H
+
+#define BCM6348_DMA_ENET0_RX	0
+#define BCM6348_DMA_ENET0_TX	1
+#define BCM6348_DMA_ENET1_RX	2
+#define BCM6348_DMA_ENET1_TX	3
+
+#endif /* __DT_BINDINGS_DMA_BCM6348_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 05/14] bmips: bcm6358: add bcm6348-iudma support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (3 preceding siblings ...)
  2018-02-12 16:38 ` [U-Boot] [RFC 04/14] bmips: bcm6348: " Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 06/14] phy: add support for internal phys Álvaro Fernández Rojas
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 arch/mips/dts/brcm,bcm6358.dtsi       | 18 ++++++++++++++++++
 include/dt-bindings/dma/bcm6358-dma.h | 17 +++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6358-dma.h

diff --git a/arch/mips/dts/brcm,bcm6358.dtsi b/arch/mips/dts/brcm,bcm6358.dtsi
index b63b53baee..1468e4f63a 100644
--- a/arch/mips/dts/brcm,bcm6358.dtsi
+++ b/arch/mips/dts/brcm,bcm6358.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6358-clock.h>
+#include <dt-bindings/dma/bcm6358-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6358-reset.h>
 #include "skeleton.dtsi"
@@ -191,5 +192,22 @@
 
 			status = "disabled";
 		};
+
+		iudma: dma-controller at fffe5000 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe5000 0x24>,
+			      <0xfffe5100 0x80>,
+			      <0xfffe5200 0x80>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <8>;
+			clocks = <&periph_clk BCM6358_CLK_EMUSB>,
+				 <&periph_clk BCM6358_CLK_USBSU>,
+				 <&periph_clk BCM6358_CLK_EPHY>;
+			resets = <&periph_rst BCM6358_RST_ENET>,
+				 <&periph_rst BCM6358_RST_EPHY>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6358-dma.h b/include/dt-bindings/dma/bcm6358-dma.h
new file mode 100644
index 0000000000..3b1fcf8540
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6358-dma.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6358_H
+#define __DT_BINDINGS_DMA_BCM6358_H
+
+#define BCM6358_DMA_ENET0_RX	0
+#define BCM6358_DMA_ENET0_TX	1
+#define BCM6358_DMA_ENET1_RX	2
+#define BCM6358_DMA_ENET1_TX	3
+
+#endif /* __DT_BINDINGS_DMA_BCM6358_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 06/14] phy: add support for internal phys
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (4 preceding siblings ...)
  2018-02-12 16:38 ` [U-Boot] [RFC 05/14] bmips: bcm6358: " Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 07/14] net: add support for bcm6348-enet Álvaro Fernández Rojas
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 include/phy.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/phy.h b/include/phy.h
index 0543ec10c2..8f3e53db01 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -50,6 +50,7 @@
 
 
 typedef enum {
+	PHY_INTERFACE_MODE_INTERNAL,
 	PHY_INTERFACE_MODE_MII,
 	PHY_INTERFACE_MODE_GMII,
 	PHY_INTERFACE_MODE_SGMII,
@@ -72,6 +73,7 @@ typedef enum {
 } phy_interface_t;
 
 static const char *phy_interface_strings[] = {
+	[PHY_INTERFACE_MODE_INTERNAL]		= "internal",
 	[PHY_INTERFACE_MODE_MII]		= "mii",
 	[PHY_INTERFACE_MODE_GMII]		= "gmii",
 	[PHY_INTERFACE_MODE_SGMII]		= "sgmii",
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 07/14] net: add support for bcm6348-enet
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (5 preceding siblings ...)
  2018-02-12 16:38 ` [U-Boot] [RFC 06/14] phy: add support for internal phys Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 08/14] bmips: bcm6338: " Álvaro Fernández Rojas
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 drivers/net/Kconfig            |   9 +
 drivers/net/Makefile           |   1 +
 drivers/net/bcm6348-eth.c      | 517 +++++++++++++++++++++++++++++++++++++++++
 include/configs/bmips_common.h |   5 +-
 4 files changed, 531 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/bcm6348-eth.c

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index de1947ccc1..12a231cc99 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -71,6 +71,15 @@ config BCM_SF2_ETH_GMAC
 	  by the BCM_SF2_ETH driver.
 	  Say Y to any bcmcygnus based platforms.
 
+config BCM6348_ETH
+	bool "BCM6348 EMAC support"
+	depends on DM_ETH && ARCH_BMIPS
+	select DMA
+	select MII
+	select PHYLIB
+	help
+	  This driver supports the BCM6348 Ethernet MAC.
+
 config DWC_ETH_QOS
 	bool "Synopsys DWC Ethernet QOS device support"
 	depends on DM_ETH
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index ac5443c752..282adbc775 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
 obj-$(CONFIG_AG7XXX) += ag7xxx.o
 obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
+obj-$(CONFIG_BCM6348_ETH) += bcm6348-eth.o
 obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
 obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
 obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
diff --git a/drivers/net/bcm6348-eth.c b/drivers/net/bcm6348-eth.c
new file mode 100644
index 0000000000..890b7d5396
--- /dev/null
+++ b/drivers/net/bcm6348-eth.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma.h>
+#include <miiphy.h>
+#include <net.h>
+#include <phy.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+
+#define ETH_ZLEN			60
+
+#define ETH_TX_WATERMARK		32
+#define ETH_MAX_MTU_SIZE		1518
+
+#define ETH_TIMEOUT			100
+
+/* ETH Receiver Configuration register */
+#define ETH_RXCFG_REG			0x00
+#define ETH_RXCFG_ENFLOW_SHIFT		5
+#define ETH_RXCFG_ENFLOW_MASK		(1 << ETH_RXCFG_ENFLOW_SHIFT)
+
+/* ETH Receive Maximum Length register */
+#define ETH_RXMAXLEN_REG		0x04
+#define ETH_RXMAXLEN_SHIFT		0
+#define ETH_RXMAXLEN_MASK		(0x7ff << ETH_RXMAXLEN_SHIFT)
+
+/* ETH Transmit Maximum Length register */
+#define ETH_TXMAXLEN_REG		0x08
+#define ETH_TXMAXLEN_SHIFT		0
+#define ETH_TXMAXLEN_MASK		(0x7ff << ETH_TXMAXLEN_SHIFT)
+
+/* MII Status/Control register */
+#define MII_SC_REG			0x10
+#define MII_SC_MDCFREQDIV_SHIFT		0
+#define MII_SC_MDCFREQDIV_MASK		(0x7f << MII_SC_MDCFREQDIV_SHIFT)
+#define MII_SC_PREAMBLE_EN_SHIFT	7
+#define MII_SC_PREAMBLE_EN_MASK		(1 << MII_SC_PREAMBLE_EN_SHIFT)
+
+/* MII Data register */
+#define MII_DAT_REG			0x14
+#define MII_DAT_DATA_SHIFT		0
+#define MII_DAT_DATA_MASK		(0xffff << MII_DAT_DATA_SHIFT)
+#define MII_DAT_TA_SHIFT		16
+#define MII_DAT_TA_MASK			(0x3 << MII_DAT_TA_SHIFT)
+#define MII_DAT_REG_SHIFT		18
+#define MII_DAT_REG_MASK		(0x1f << MII_DAT_REG_SHIFT)
+#define MII_DAT_PHY_SHIFT		23
+#define MII_DAT_PHY_MASK		(0x1f << MII_DAT_PHY_SHIFT)
+#define MII_DAT_OP_SHIFT		28
+#define MII_DAT_OP_WRITE		(0x5 << MII_DAT_OP_SHIFT)
+#define MII_DAT_OP_READ			(0x6 << MII_DAT_OP_SHIFT)
+
+/* ETH Interrupts Mask register */
+#define ETH_IRMASK_REG			0x18
+
+/* ETH Interrupts register */
+#define ETH_IR_REG			0x1c
+#define ETH_IR_MII_SHIFT		0
+#define ETH_IR_MII_MASK			(1 << ETH_IR_MII_SHIFT)
+
+/* ETH Control register */
+#define ETH_CTL_REG			0x2c
+#define ETH_CTL_ENABLE_SHIFT		0
+#define ETH_CTL_ENABLE_MASK		(1 << ETH_CTL_ENABLE_SHIFT)
+#define ETH_CTL_DISABLE_SHIFT		1
+#define ETH_CTL_DISABLE_MASK		(1 << ETH_CTL_DISABLE_SHIFT)
+#define ETH_CTL_RESET_SHIFT		2
+#define ETH_CTL_RESET_MASK		(1 << ETH_CTL_RESET_SHIFT)
+#define ETH_CTL_EPHY_SHIFT		3
+#define ETH_CTL_EPHY_MASK		(1 << ETH_CTL_EPHY_SHIFT)
+
+/* ETH Transmit Control register */
+#define ETH_TXCTL_REG			0x30
+#define ETH_TXCTL_FD_SHIFT		0
+#define ETH_TXCTL_FD_MASK		(1 << ETH_TXCTL_FD_SHIFT)
+
+/* ETH Transmit Watermask register */
+#define ETH_TXWMARK_REG			0x34
+#define ETH_TXWMARK_WM_SHIFT		0
+#define ETH_TXWMARK_WM_MASK		(0x3f << ETH_TXWMARK_WM_SHIFT)
+
+/* MIB Control register */
+#define MIB_CTL_REG			0x38
+#define MIB_CTL_RDCLEAR_SHIFT		0
+#define MIB_CTL_RDCLEAR_MASK		(1 << MIB_CTL_RDCLEAR_SHIFT)
+
+/* ETH Perfect Match registers */
+#define ETH_PM_CNT			4
+#define ETH_PML_REG(x)			(0x58 + (x) * 0x8)
+#define ETH_PMH_REG(x)			(0x5c + (x) * 0x8)
+#define ETH_PMH_VALID_SHIFT		16
+#define ETH_PMH_VALID_MASK		(1 << ETH_PMH_VALID_SHIFT)
+
+/* MIB Counters registers */
+#define MIB_REG_CNT			55
+#define MIB_REG(x)			(0x200 + (x) * 4)
+
+/* ETH data */
+struct bcm6348_eth_priv {
+	void __iomem *base;
+	/* DMA */
+	struct dma rx_dma;
+	struct dma tx_dma;
+	/* PHY */
+	int phy_id;
+	struct phy_device *phy_dev;
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void bcm6348_eth_mac_disable(struct bcm6348_eth_priv *priv)
+{
+	/* disable emac */
+	clrsetbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK,
+			ETH_CTL_DISABLE_MASK);
+
+	/* wait until emac is disabled */
+	if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
+			      ETH_CTL_DISABLE_MASK, false,
+			      ETH_TIMEOUT, false))
+		pr_err("error disabling emac\n");
+}
+
+static void bcm6348_eth_mac_enable(struct bcm6348_eth_priv *priv)
+{
+	setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK);
+}
+
+static void bcm6348_eth_mac_reset(struct bcm6348_eth_priv *priv)
+{
+	/* reset emac */
+	writel_be(ETH_CTL_RESET_MASK, priv->base + ETH_CTL_REG);
+	wmb();
+
+	/* wait until emac is reset */
+	if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
+			      ETH_CTL_RESET_MASK, false,
+			      ETH_TIMEOUT, false))
+		pr_err("error resetting emac\n");
+}
+
+static int bcm6348_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	return dma_receive(&priv->rx_dma, (void *)packetp);
+}
+
+static int bcm6348_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	length = max(length, ETH_ZLEN);
+
+	return dma_send(&priv->tx_dma, (void **)packet, length);
+}
+
+static int bcm6348_eth_adjust_link(struct udevice *dev,
+				   struct phy_device *phydev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* mac duplex parameters */
+	if (phydev->duplex)
+		setbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
+	else
+		clrbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
+
+	/* rx flow control (pause frame handling) */
+	if (phydev->pause)
+		setbits_be32(priv->base + ETH_RXCFG_REG,
+			     ETH_RXCFG_ENFLOW_MASK);
+	else
+		clrbits_be32(priv->base + ETH_RXCFG_REG,
+			     ETH_RXCFG_ENFLOW_MASK);
+
+	return 0;
+}
+
+static int bcm6348_eth_start(struct udevice *dev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	int ret, i;
+
+	/* enable dma rx channel */
+	dma_enable(&priv->rx_dma);
+
+	/* enable dma tx channel */
+	dma_enable(&priv->tx_dma);
+
+	ret = phy_startup(priv->phy_dev);
+	if (ret) {
+		pr_err("could not initialize phy\n");
+		return ret;
+	}
+
+	if (!priv->phy_dev->link) {
+		pr_err("no phy link\n");
+		return -EIO;
+	}
+
+	bcm6348_eth_adjust_link(dev, priv->phy_dev);
+
+	/* zero mib counters */
+	for (i = 0; i < MIB_REG_CNT; i++)
+		writel_be(0, MIB_REG(i));
+
+	/* enable rx flow control */
+	setbits_be32(priv->base + ETH_RXCFG_REG, ETH_RXCFG_ENFLOW_MASK);
+
+	/* set max rx/tx length */
+	writel_be((ETH_MAX_MTU_SIZE << ETH_RXMAXLEN_SHIFT) &
+		  ETH_RXMAXLEN_MASK, priv->base + ETH_RXMAXLEN_REG);
+	writel_be((ETH_MAX_MTU_SIZE << ETH_TXMAXLEN_SHIFT) &
+		   ETH_TXMAXLEN_MASK, priv->base + ETH_TXMAXLEN_REG);
+
+	/* set correct transmit fifo watermark */
+	writel_be((ETH_TX_WATERMARK << ETH_TXWMARK_WM_SHIFT) &
+		  ETH_TXWMARK_WM_MASK, priv->base + ETH_TXWMARK_REG);
+
+	/* enable emac */
+	bcm6348_eth_mac_enable(priv);
+
+	/* clear interrupts */
+	writel_be(0, priv->base + ETH_IRMASK_REG);
+
+	return 0;
+}
+
+static void bcm6348_eth_stop(struct udevice *dev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* disable dma rx channel */
+	dma_disable(&priv->rx_dma);
+
+	/* disable dma tx channel */
+	dma_disable(&priv->tx_dma);
+
+	/* disable emac */
+	bcm6348_eth_mac_disable(priv);
+}
+
+static int bcm6348_eth_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	bool running = false;
+
+	/* check if emac is running */
+	if (readl_be(priv->base + ETH_CTL_REG) & ETH_CTL_ENABLE_MASK)
+		running = true;
+
+	/* disable emac */
+	if (running)
+		bcm6348_eth_mac_disable(priv);
+
+	/* set mac address */
+	writel_be((pdata->enetaddr[2] << 24) | (pdata->enetaddr[3]) << 16 |
+		  (pdata->enetaddr[4]) << 8 | (pdata->enetaddr[5]),
+		  priv->base + ETH_PML_REG(0));
+	writel_be((pdata->enetaddr[1]) | (pdata->enetaddr[0] << 8) |
+		  ETH_PMH_VALID_MASK, priv->base + ETH_PMH_REG(0));
+
+	/* enable emac */
+	if (running)
+		bcm6348_eth_mac_enable(priv);
+
+	return 0;
+}
+
+static const struct eth_ops bcm6348_eth_ops = {
+	.recv = bcm6348_eth_recv,
+	.send = bcm6348_eth_send,
+	.start = bcm6348_eth_start,
+	.stop = bcm6348_eth_stop,
+	.write_hwaddr = bcm6348_eth_write_hwaddr,
+};
+
+static const struct udevice_id bcm6348_eth_ids[] = {
+	{ .compatible = "brcm,bcm6348-enet", },
+	{ /* sentinel */ }
+};
+
+static int bcm6348_mdio_op(void __iomem *base, uint32_t data)
+{
+	/* make sure mii interrupt status is cleared */
+	writel_be(ETH_IR_MII_MASK, base + ETH_IR_REG);
+
+	/* issue mii op */
+	writel_be(data, base + MII_DAT_REG);
+
+	/* wait until emac is disabled */
+	return wait_for_bit_be32(base + ETH_IR_REG,
+				 ETH_IR_MII_MASK, true,
+				 ETH_TIMEOUT, false);
+}
+
+static int bcm6348_mdio_read(struct mii_dev *bus, int addr, int devaddr,
+			     int reg)
+{
+	void __iomem *base = bus->priv;
+	uint32_t val;
+
+	val = MII_DAT_OP_READ;
+	val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
+	val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
+	val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
+
+	if (bcm6348_mdio_op(base, val)) {
+		pr_err("%s: timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	val = readl_be(base + MII_DAT_REG) & MII_DAT_DATA_MASK;
+	val >>= MII_DAT_DATA_SHIFT;
+
+	return val;
+}
+
+static int bcm6348_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
+			      int reg, u16 value)
+{
+	void __iomem *base = bus->priv;
+	uint32_t val;
+
+	val = MII_DAT_OP_WRITE;
+	val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
+	val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
+	val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
+	val |= (value << MII_DAT_DATA_SHIFT) & MII_DAT_DATA_MASK;
+
+	if (bcm6348_mdio_op(base, val)) {
+		pr_err("%s: timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int bcm6348_mdio_init(const char *name, void __iomem *base)
+{
+	struct mii_dev *bus;
+
+	bus = mdio_alloc();
+	if (!bus) {
+		pr_err("%s: failed to allocate MDIO bus\n", __func__);
+		return -ENOMEM;
+	}
+
+	bus->read = bcm6348_mdio_read;
+	bus->write = bcm6348_mdio_write;
+	bus->priv = base;
+	snprintf(bus->name, sizeof(bus->name), "%s", name);
+
+	return mdio_register(bus);
+}
+
+static int bcm6348_phy_init(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	struct mii_dev *bus;
+
+	/* get mii bus */
+	bus = miiphy_get_dev_by_name(dev->name);
+
+	/* phy connect */
+	priv->phy_dev = phy_connect(bus, priv->phy_id, dev,
+				    pdata->phy_interface);
+	if (!priv->phy_dev) {
+		pr_err("%s: no phy device\n", __func__);
+		return -ENODEV;
+	}
+
+	priv->phy_dev->supported = (SUPPORTED_10baseT_Half |
+				    SUPPORTED_10baseT_Full |
+				    SUPPORTED_100baseT_Half |
+				    SUPPORTED_100baseT_Full |
+				    SUPPORTED_Autoneg |
+				    SUPPORTED_Pause |
+				    SUPPORTED_MII);
+	priv->phy_dev->advertising = priv->phy_dev->supported;
+
+	/* phy config */
+	phy_config(priv->phy_dev);
+
+	return 0;
+}
+
+static int bcm6348_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	void *blob = (void *)gd->fdt_blob;
+	int node = dev_of_offset(dev);
+	const char *phy_mode;
+	fdt_addr_t addr;
+	int phy_node, ret, i;
+
+	/* get base address */
+	addr = devfdt_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	/* get phy mode */
+	pdata->phy_interface = PHY_INTERFACE_MODE_NONE;
+	phy_mode = fdt_getprop(blob, node, "phy-mode", NULL);
+	if (phy_mode)
+		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_NONE)
+		return -ENODEV;
+
+	/* get phy */
+	phy_node = fdtdec_lookup_phandle(blob, node, "phy");
+	if (phy_node >= 0)
+		priv->phy_id = fdtdec_get_int(blob, phy_node, "reg", -1);
+	else
+		return -EINVAL;
+
+	/* get dma channels */
+	ret = dma_get_by_name(dev, "tx", &priv->tx_dma);
+	if (ret)
+		return -EINVAL;
+
+	ret = dma_get_by_name(dev, "rx", &priv->rx_dma);
+	if (ret)
+		return -EINVAL;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+		if (clk_enable(&clk))
+			pr_err("failed to enable clock %d\n", i);
+		clk_free(&clk);
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+		if (reset_deassert(&reset))
+			pr_err("failed to deassert reset %d\n", i);
+		reset_free(&reset);
+	}
+
+	/* get base addr */
+	priv->base = ioremap(addr, 0);
+	pdata->iobase = (phys_addr_t) priv->base;
+
+	/* disable emac */
+	bcm6348_eth_mac_disable(priv);
+
+	/* reset emac */
+	bcm6348_eth_mac_reset(priv);
+
+	/* select correct mii interface */
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_INTERNAL)
+		clrbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
+	else
+		setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
+
+	/* turn on mdc clock */
+	writel_be((0x1f << MII_SC_MDCFREQDIV_SHIFT) |
+		  MII_SC_PREAMBLE_EN_MASK, priv->base + MII_SC_REG);
+
+	/* set mib counters to not clear when read */
+	clrbits_be32(priv->base + MIB_CTL_REG, MIB_CTL_RDCLEAR_MASK);
+
+	/* initialize perfect match registers */
+	for (i = 0; i < ETH_PM_CNT; i++) {
+		writel_be(0, priv->base + ETH_PML_REG(i));
+		writel_be(0, priv->base + ETH_PMH_REG(i));
+	}
+
+	/* init mii bus */
+	ret = bcm6348_mdio_init(dev->name, priv->base);
+	if (ret)
+		return ret;
+
+	/* init phy */
+	ret = bcm6348_phy_init(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_eth) = {
+	.name = "bcm6348_eth",
+	.id = UCLASS_ETH,
+	.of_match = bcm6348_eth_ids,
+	.ops = &bcm6348_eth_ops,
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.priv_auto_alloc_size = sizeof(struct bcm6348_eth_priv),
+	.probe = bcm6348_eth_probe,
+};
diff --git a/include/configs/bmips_common.h b/include/configs/bmips_common.h
index 38bf7a272b..eb66512f67 100644
--- a/include/configs/bmips_common.h
+++ b/include/configs/bmips_common.h
@@ -7,6 +7,9 @@
 #ifndef __CONFIG_BMIPS_COMMON_H
 #define __CONFIG_BMIPS_COMMON_H
 
+/* ETH */
+#define CONFIG_PHY_RESET_DELAY		20
+
 /* UART */
 #define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200, \
 					  230400, 500000, 1500000 }
@@ -17,7 +20,7 @@
 
 /* Memory usage */
 #define CONFIG_SYS_MAXARGS		24
-#define CONFIG_SYS_MALLOC_LEN		(1024 * 1024)
+#define CONFIG_SYS_MALLOC_LEN		(2 * 1024 * 1024)
 #define CONFIG_SYS_BOOTPARAMS_LEN	(128 * 1024)
 #define CONFIG_SYS_CBSIZE		512
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 08/14] bmips: bcm6338: add support for bcm6348-enet
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (6 preceding siblings ...)
  2018-02-12 16:38 ` [U-Boot] [RFC 07/14] net: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 09/14] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 arch/mips/dts/brcm,bcm6338.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6338.dtsi b/arch/mips/dts/brcm,bcm6338.dtsi
index 4125f71d9f..621278c9d1 100644
--- a/arch/mips/dts/brcm,bcm6338.dtsi
+++ b/arch/mips/dts/brcm,bcm6338.dtsi
@@ -145,5 +145,20 @@
 			dma-channels = <6>;
 			resets = <&periph_rst BCM6338_RST_DMAMEM>;
 		};
+
+		enet: ethernet at fffe2800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe2800 0x2dc>;
+			clocks = <&periph_clk BCM6338_CLK_ENET>;
+			resets = <&periph_rst BCM6338_RST_ENET>;
+			dmas = <&iudma BCM6338_DMA_ENET_RX>,
+			       <&iudma BCM6338_DMA_ENET_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
 	};
 };
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 09/14] bmips: enable f@st1704 enet support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (7 preceding siblings ...)
  2018-02-12 16:38 ` [U-Boot] [RFC 08/14] bmips: bcm6338: " Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 10/14] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 arch/mips/dts/sagem,f at st1704.dts     | 12 ++++++++++++
 configs/sagem_f at st1704_ram_defconfig |  9 ++++++++-
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/sagem,f at st1704.dts b/arch/mips/dts/sagem,f at st1704.dts
index dd0e5b8b7c..99d031f10a 100644
--- a/arch/mips/dts/sagem,f at st1704.dts
+++ b/arch/mips/dts/sagem,f at st1704.dts
@@ -40,6 +40,18 @@
 	};
 };
 
+&enet {
+	status = "okay";
+	phy = <&enetphy>;
+	phy-mode = "mii";
+
+	enetphy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio {
 	status = "okay";
 };
diff --git a/configs/sagem_f at st1704_ram_defconfig b/configs/sagem_f at st1704_ram_defconfig
index 0adcd46d51..1a640781b7 100644
--- a/configs/sagem_f at st1704_ram_defconfig
+++ b/configs/sagem_f at st1704_ram_defconfig
@@ -28,11 +28,15 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_SF=y
 CONFIG_CMD_SPI=y
-# CONFIG_CMD_NET is not set
+CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -41,6 +45,9 @@ CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_DM_RESET=y
 CONFIG_RESET_BCM6345=y
 # CONFIG_SPL_SERIAL_PRESENT is not set
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 10/14] bmips: bcm6348: add support for bcm6348-enet
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (8 preceding siblings ...)
  2018-02-12 16:38 ` [U-Boot] [RFC 09/14] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 11/14] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 arch/mips/dts/brcm,bcm6348.dtsi | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6348.dtsi b/arch/mips/dts/brcm,bcm6348.dtsi
index d774c59665..e540865019 100644
--- a/arch/mips/dts/brcm,bcm6348.dtsi
+++ b/arch/mips/dts/brcm,bcm6348.dtsi
@@ -162,6 +162,32 @@
 			u-boot,dm-pre-reloc;
 		};
 
+		enet0: ethernet at fffe6000 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe6000 0x2dc>;
+			dmas = <&iudma BCM6348_DMA_ENET0_RX>,
+			       <&iudma BCM6348_DMA_ENET0_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		enet1: ethernet at fffe6800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe6800 0x2dc>;
+			dmas = <&iudma BCM6348_DMA_ENET1_RX>,
+			       <&iudma BCM6348_DMA_ENET1_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
 		iudma: dma-controller at fffe7000 {
 			compatible = "brcm,bcm6348-iudma";
 			reg = <0xfffe7000 0x1c>,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 11/14] bmips: enable ct-5361 enet support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (9 preceding siblings ...)
  2018-02-12 16:38 ` [U-Boot] [RFC 10/14] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 12/14] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 arch/mips/dts/comtrend,ct-5361.dts    | 12 ++++++++++++
 configs/comtrend_ct5361_ram_defconfig |  8 +++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/comtrend,ct-5361.dts b/arch/mips/dts/comtrend,ct-5361.dts
index 74dc09046c..a78aa877fc 100644
--- a/arch/mips/dts/comtrend,ct-5361.dts
+++ b/arch/mips/dts/comtrend,ct-5361.dts
@@ -35,6 +35,18 @@
 	};
 };
 
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/comtrend_ct5361_ram_defconfig b/configs/comtrend_ct5361_ram_defconfig
index 8b842606f5..0737772dd2 100644
--- a/configs/comtrend_ct5361_ram_defconfig
+++ b/configs/comtrend_ct5361_ram_defconfig
@@ -26,11 +26,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -38,6 +41,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6348_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 12/14] bmips: bcm6358: add support for bcm6348-enet
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (10 preceding siblings ...)
  2018-02-12 16:38 ` [U-Boot] [RFC 11/14] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 13/14] bmips: enable hg556a enet support Álvaro Fernández Rojas
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 arch/mips/dts/brcm,bcm6358.dtsi | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6358.dtsi b/arch/mips/dts/brcm,bcm6358.dtsi
index 1468e4f63a..04329864c2 100644
--- a/arch/mips/dts/brcm,bcm6358.dtsi
+++ b/arch/mips/dts/brcm,bcm6358.dtsi
@@ -193,6 +193,34 @@
 			status = "disabled";
 		};
 
+		enet0: ethernet at fffe4000 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe4000 0x2dc>;
+			clocks = <&periph_clk BCM6358_CLK_ENET0>;
+			dmas = <&iudma BCM6358_DMA_ENET0_RX>,
+			       <&iudma BCM6358_DMA_ENET0_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		enet1: ethernet at fffe4800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe4800 0x2dc>;
+			clocks = <&periph_clk BCM6358_CLK_ENET1>;
+			dmas = <&iudma BCM6358_DMA_ENET1_RX>,
+			       <&iudma BCM6358_DMA_ENET1_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
 		iudma: dma-controller at fffe5000 {
 			compatible = "brcm,bcm6348-iudma";
 			reg = <0xfffe5000 0x24>,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 13/14] bmips: enable hg556a enet support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (11 preceding siblings ...)
  2018-02-12 16:38 ` [U-Boot] [RFC 12/14] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-12 16:38 ` [U-Boot] [RFC 14/14] bmips: enable nb4-ser " Álvaro Fernández Rojas
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 arch/mips/dts/huawei,hg556a.dts     | 12 ++++++++++++
 configs/huawei_hg556a_ram_defconfig |  8 +++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/huawei,hg556a.dts b/arch/mips/dts/huawei,hg556a.dts
index a1e9c15ab9..2f99e0905c 100644
--- a/arch/mips/dts/huawei,hg556a.dts
+++ b/arch/mips/dts/huawei,hg556a.dts
@@ -94,6 +94,18 @@
 	status = "okay";
 };
 
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/huawei_hg556a_ram_defconfig b/configs/huawei_hg556a_ram_defconfig
index 7f7f34ed61..c7c7c6554f 100644
--- a/configs/huawei_hg556a_ram_defconfig
+++ b/configs/huawei_hg556a_ram_defconfig
@@ -26,11 +26,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -38,6 +41,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6358_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 14/14] bmips: enable nb4-ser enet support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (12 preceding siblings ...)
  2018-02-12 16:38 ` [U-Boot] [RFC 13/14] bmips: enable hg556a enet support Álvaro Fernández Rojas
@ 2018-02-12 16:38 ` Álvaro Fernández Rojas
  2018-02-19 17:26 ` [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-12 16:38 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 arch/mips/dts/sfr,nb4-ser.dts     | 24 ++++++++++++++++++++++++
 configs/sfr_nb4-ser_ram_defconfig |  8 +++++++-
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/sfr,nb4-ser.dts b/arch/mips/dts/sfr,nb4-ser.dts
index 473372faa1..73db45f9ea 100644
--- a/arch/mips/dts/sfr,nb4-ser.dts
+++ b/arch/mips/dts/sfr,nb4-ser.dts
@@ -54,6 +54,30 @@
 	status = "okay";
 };
 
+&enet0 {
+	status = "okay";
+	phy = <&enet0phy>;
+	phy-mode = "internal";
+
+	enet0phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/sfr_nb4-ser_ram_defconfig b/configs/sfr_nb4-ser_ram_defconfig
index fc323d879d..07b49a1a77 100644
--- a/configs/sfr_nb4-ser_ram_defconfig
+++ b/configs/sfr_nb4-ser_ram_defconfig
@@ -27,11 +27,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -40,6 +43,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6358_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (13 preceding siblings ...)
  2018-02-12 16:38 ` [U-Boot] [RFC 14/14] bmips: enable nb4-ser " Álvaro Fernández Rojas
@ 2018-02-19 17:26 ` Álvaro Fernández Rojas
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-19 17:26 UTC (permalink / raw)
  To: u-boot

No comments about DMA?

2018-02-12 17:38 GMT+01:00 Álvaro Fernández Rojas <noltari@gmail.com>:

> In order to add bcm6348-enet support, dma-uclass must be extended to
> support
> dma channels and rewordked to operate like the other dm uclass (clk,
> reset...).
>
> This is an RFC, so please give you feedback on the things that I should
> fix or rework.
>
> Álvaro Fernández Rojas (14):
>   dma: add dma channels support and improve uclass
>   dma: add bcm6348-iudma support
>   bmips: bcm6338: add bcm6348-iudma support
>   bmips: bcm6348: add bcm6348-iudma support
>   bmips: bcm6358: add bcm6348-iudma support
>   phy: add support for internal phys
>   net: add support for bcm6348-enet
>   bmips: bcm6338: add support for bcm6348-enet
>   bmips: enable f at st1704 enet support
>   bmips: bcm6348: add support for bcm6348-enet
>   bmips: enable ct-5361 enet support
>   bmips: bcm6358: add support for bcm6348-enet
>   bmips: enable hg556a enet support
>   bmips: enable nb4-ser enet support
>
>  arch/mips/dts/brcm,bcm6338.dtsi       |  29 ++
>  arch/mips/dts/brcm,bcm6348.dtsi       |  42 +++
>  arch/mips/dts/brcm,bcm6358.dtsi       |  46 +++
>  arch/mips/dts/comtrend,ct-5361.dts    |  12 +
>  arch/mips/dts/huawei,hg556a.dts       |  12 +
>  arch/mips/dts/sagem,f at st1704.dts      |  12 +
>  arch/mips/dts/sfr,nb4-ser.dts         |  24 ++
>  configs/comtrend_ct5361_ram_defconfig |   8 +-
>  configs/huawei_hg556a_ram_defconfig   |   8 +-
>  configs/sagem_f at st1704_ram_defconfig  |   9 +-
>  configs/sfr_nb4-ser_ram_defconfig     |   8 +-
>  drivers/dma/Kconfig                   |   8 +
>  drivers/dma/Makefile                  |   1 +
>  drivers/dma/bcm6348-iudma.c           | 498 ++++++++++++++++++++++++++++++
> ++
>  drivers/dma/dma-uclass.c              | 212 +++++++++++---
>  drivers/mtd/spi/sf-uclass.c           |  17 ++
>  drivers/mtd/spi/spi_flash.c           |  11 +-
>  drivers/net/Kconfig                   |   9 +
>  drivers/net/Makefile                  |   1 +
>  drivers/net/bcm6348-eth.c             | 517 ++++++++++++++++++++++++++++++
> ++++
>  include/configs/bmips_common.h        |   5 +-
>  include/dma-uclass.h                  | 110 ++++++++
>  include/dma.h                         | 226 +++++++++++----
>  include/dt-bindings/dma/bcm6338-dma.h |  15 +
>  include/dt-bindings/dma/bcm6348-dma.h |  17 ++
>  include/dt-bindings/dma/bcm6358-dma.h |  17 ++
>  include/phy.h                         |   2 +
>  include/spi_flash.h                   |   3 +
>  28 files changed, 1780 insertions(+), 99 deletions(-)
>  create mode 100644 drivers/dma/bcm6348-iudma.c
>  create mode 100644 drivers/net/bcm6348-eth.c
>  create mode 100644 include/dma-uclass.h
>  create mode 100644 include/dt-bindings/dma/bcm6338-dma.h
>  create mode 100644 include/dt-bindings/dma/bcm6348-dma.h
>  create mode 100644 include/dt-bindings/dma/bcm6358-dma.h
>
> --
> 2.11.0
>
>

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC 01/14] dma: add dma channels support and improve uclass
  2018-02-12 16:38 ` [U-Boot] [RFC 01/14] dma: add dma channels support and improve uclass Álvaro Fernández Rojas
@ 2018-02-20  8:24   ` Vignesh R
  0 siblings, 0 replies; 106+ messages in thread
From: Vignesh R @ 2018-02-20  8:24 UTC (permalink / raw)
  To: u-boot

Please add a commit message as this is a pretty big change providing a
overview what is being added and why?

On Monday 12 February 2018 10:08 PM, Álvaro Fernández Rojas wrote:
> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
> ---
>  drivers/dma/dma-uclass.c    | 212 ++++++++++++++++++++++++++++++++++-------


This patch definitely breaks drivers/dma/ti-edma3.c which implements
current definition of dma-uclass.

One of the assumption of current dma_memcpy() implementation is that the
client's DT node need not have "dmas" entry to specify which DMA
provider and DMA channel to use for dma memcpy. (This is true in linux
kernel as well). Most DMA HWs have general purpose channels that are not
tied to any peripherals and can be used for mem to mem transfers.
So, if the client device's DT node does not populate "dmas" property
then dma_memcpy() API should try to find a DMA provider that supports
memcpy operation, request a memcpy capable channel from the provider and
use it to transfer data. Please keep the current behavior as is.
Or, provide a API for clients to request such a channel.

>  drivers/mtd/spi/sf-uclass.c |  17 ++++
>  drivers/mtd/spi/spi_flash.c |  11 ++-
>  include/dma-uclass.h        | 110 +++++++++++++++++++++
>  include/dma.h               | 226 +++++++++++++++++++++++++++++++++-----------
>  include/spi_flash.h         |   3 +
>  6 files changed, 485 insertions(+), 94 deletions(-)
>  create mode 100644 include/dma-uclass.h
> 
> diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
> index 3d0ce22fbc..7d04d98493 100644
> --- a/drivers/dma/dma-uclass.c
> +++ b/drivers/dma/dma-uclass.c
> @@ -1,59 +1,176 @@
>  /*
> - * Direct Memory Access U-Class driver
> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
> + * Copyright (C) 2015 Texas Instruments Incorporated, <www.ti.com>
> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
>   *
> - * (C) Copyright 2015
> - *     Texas Instruments Incorporated, <www.ti.com>
> - *
> - * Author: Mugunthan V N <mugunthanvnm@ti.com>
> - *
> - * SPDX-License-Identifier:     GPL-2.0+
> + * SPDX-License-Identifier:	GPL-2.0+
>   */
>  
>  #include <common.h>
> -#include <dma.h>
>  #include <dm.h>
> -#include <dm/uclass-internal.h>
> -#include <dm/device-internal.h>
> +#include <dma.h>
> +#include <dma-uclass.h>
> +#include <dt-structs.h>
>  #include <errno.h>
>  
>  DECLARE_GLOBAL_DATA_PTR;
>  
> -int dma_get_device(u32 transfer_type, struct udevice **devp)
> +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)
>  {
> -	struct udevice *dev;
>  	int ret;
>  
> -	for (ret = uclass_first_device(UCLASS_DMA, &dev); dev && !ret;
> -	     ret = uclass_next_device(&dev)) {
> -		struct dma_dev_priv *uc_priv;
> +	if (index != 0)
> +		return -ENOSYS;
> +	ret = uclass_get_device(UCLASS_DMA, 0, &dma->dev);
> +	if (ret)
> +		return ret;
> +	dma->id = cells[0].id;
>  
> -		uc_priv = dev_get_uclass_priv(dev);
> -		if (uc_priv->supported & transfer_type)
> -			break;
> -	}
> +	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 (!dev) {
> -		pr_err("No DMA device found that supports %x type\n",
> -		      transfer_type);
> -		return -EPROTONOSUPPORT;
> +	if (args->args_count > 1) {
> +		pr_err("Invaild args_count: %d\n", args->args_count);
> +		return -EINVAL;
>  	}
>  
> -	*devp = dev;
> +	if (args->args_count)
> +		dma->id = args->args[0];
> +	else
> +		dma->id = 0;
>  
> -	return ret;
> +	return 0;
>  }
>  
> -int dma_memcpy(void *dst, void *src, size_t len)
> +int dma_get_by_index(struct udevice *dev, int index, struct dma *dma)
>  {
> -	struct udevice *dev;
> -	const struct dma_ops *ops;
>  	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);
>  
> -	ret = dma_get_device(DMA_SUPPORTS_MEM_TO_MEM, &dev);
> -	if (ret < 0)
> +	assert(dma);
> +	ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
> +					     "dmas", "#dma-cells", 0, index,
> +					     &args);
> +	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);
> +	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 0? I guess you meant to return -ENOSYS or something.

> +
> +	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;
> +

Same as above

> +	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_memcpy(struct dma *dma, void *dst, void *src, size_t len)
> +{
> +	struct dma_ops *ops = dma_dev_ops(dma->dev);
> +
> +	debug("%s(dma=%p)\n", __func__, dma);
>  
> -	ops = device_get_ops(dev);
>  	if (!ops->transfer)
>  		return -ENOSYS;
>  
> @@ -61,12 +178,35 @@ int dma_memcpy(void *dst, void *src, size_t len)
>  	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);
> +	return ops->transfer(dma, DMA_MEM_TO_MEM, dst, src, len);
> +}
> +
> +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;

-ENOSYS?

> +
> +	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;

-ENOSYS?

> +
> +	return ops->send(dma, src, len);
>  }
>  
>  UCLASS_DRIVER(dma) = {
> -	.id		= UCLASS_DMA,
> -	.name		= "dma",
> -	.flags		= DM_UC_FLAG_SEQ_ALIAS,
> -	.per_device_auto_alloc_size = sizeof(struct dma_dev_priv),
> +	.id = UCLASS_DMA,
> +	.name = "dma",
> +	.flags = DM_UC_FLAG_SEQ_ALIAS,
>  };
> diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c
> index 83876485fe..992dead1a2 100644
> --- a/drivers/mtd/spi/sf-uclass.c
> +++ b/drivers/mtd/spi/sf-uclass.c
> @@ -6,6 +6,7 @@
>  
>  #include <common.h>
>  #include <dm.h>
> +#include <dma.h>
>  #include <spi.h>
>  #include <spi_flash.h>
>  #include <dm/device-internal.h>
> @@ -72,6 +73,22 @@ int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
>  		return ret;
>  
>  	*devp = slave->dev;
> +
> +#ifdef CONFIG_DMA
> +	if (fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(*devp),
> +				  "dmas") > 0) {
> +		struct spi_flash *priv = dev_get_uclass_priv(*devp);
> +
> +		priv->dma = calloc(1, sizeof(struct dma));
> +		if (!priv->dma)
> +			return -ENOMEM;
> +
> +		ret = dma_get_by_index(*devp, 0, priv->dma);
> +		if (ret)
> +			return -EINVAL;
> +	}
> +#endif
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
> index 294d9f9d79..8b1c6a27de 100644
> --- a/drivers/mtd/spi/spi_flash.c
> +++ b/drivers/mtd/spi/spi_flash.c
> @@ -458,10 +458,6 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
>   */
>  void __weak spi_flash_copy_mmap(void *data, void *offset, size_t len)
>  {
> -#ifdef CONFIG_DMA
> -	if (!dma_memcpy(data, offset, len))
> -		return;
> -#endif
>  	memcpy(data, offset, len);
>  }
>  
> @@ -482,7 +478,12 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
>  			return ret;
>  		}
>  		spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP);
> -		spi_flash_copy_mmap(data, flash->memory_map + offset, len);
> +		if (flash->dma)
> +			dma_memcpy(flash->dma, data,
> +				   flash->memory_map + offset, len);
> +		else
> +			spi_flash_copy_mmap(data, flash->memory_map + offset,
> +					    len);
>  		spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP_END);
>  		spi_release_bus(spi);
>  		return 0;
> diff --git a/include/dma-uclass.h b/include/dma-uclass.h
> new file mode 100644
> index 0000000000..0315e54441
> --- /dev/null
> +++ b/include/dma-uclass.h
> @@ -0,0 +1,110 @@
> +/*
> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
> + * Copyright (C) 2015 Texas Instruments Incorporated, <www.ti.com>
> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef _DMA_UCLASS_H
> +#define _DMA_UCLASS_H
> +
> +/* See dma.h for background documentation. */
> +
> +#include <dma.h>
> +#include <fdtdec.h>
> +
> +/**
> + * struct dma_ops - The functions that a DMA driver must implement.
> + */
> +struct dma_ops {
> +	/**
> +	 * 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);
> +	/**
> +	 * request - Request a translated DMA.
> +	 *
> +	 * The DMA core calls this function as the second step in
> +	 * implementing a client's dma_get_by_*() call, following a successful
> +	 * xxx_xlate() call, or as the only step in implementing a client's
> +	 * dma_request() call.
> +	 *
> +	 * @dma: The DMA struct to request; this has been filled in by
> +	 *   a previoux xxx_xlate() function call, or by the caller of
> +	 *   dma_request().
> +	 * @return 0 if OK, or a negative error code.
> +	 */
> +	int (*request)(struct dma *dma);
> +	/**
> +	 * free - Free a previously requested dma.
> +	 *
> +	 * This is the implementation of the client dma_free() API.
> +	 *
> +	 * @dma: The DMA to free.
> +	 * @return 0 if OK, or a negative error code.
> +	 */
> +	int (*free)(struct dma *dma);
> +	/**
> +	 * enable() - Enable a DMA Channel.
> +	 *
> +	 * @dma: The DMA Channel to manipulate.
> +	 * @return zero on success, or -ve error code.
> +	 */
> +	int (*enable)(struct dma *dma);
> +	/**
> +	 * disable() - Disable a DMA Channel.
> +	 *
> +	 * @dma: The DMA Channel to manipulate.
> +	 * @return zero on success, or -ve error code.
> +	 */
> +	int (*disable)(struct dma *dma);
> +	/**
> +	 * transfer() - Issue a DMA transfer.
> +	 *
> +	 * @dma: The DMA Channel to manipulate.
> +	 * @dir: The direction of data transfer.
> +	 * @dst: The destination pointer.
> +	 * @src: The source pointer.
> +	 * @len: Length of the data to be copied.
> +	 * @return zero on success, or -ve error code.
> +	 */
> +	int (*transfer)(struct dma *dma, enum dma_transfer_direction dir,
> +			void *dst, void *src, size_t len);
> +	/**
> +	 * 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 copied.
> +	 * @return zero on success, or -ve error code.
> +	 */
> +	int (*send)(struct dma *dma, void *src, size_t len);
> +

I wonder why separate send()/receive() is needed. Isn't transfer() alone
sufficient with appropriate direction flags? If its very specific to
networking use case then, please explain that more clearly as to why
this interface is provided in the comments (especially receive()
interface that does not pass length).



Regards
Vignesh
> +};
> +
> +#endif /* _DMA_UCLASS_H */
> diff --git a/include/dma.h b/include/dma.h
> index 71fa77f2ea..3632e3256d 100644
> --- a/include/dma.h
> +++ b/include/dma.h
> @@ -1,86 +1,206 @@
>  /*
> - * (C) Copyright 2015
> - *     Texas Instruments Incorporated, <www.ti.com>
> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
> + * Copyright (C) 2015 Texas Instruments Incorporated, <www.ti.com>
> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
>   *
> - * SPDX-License-Identifier:     GPL-2.0+
> + * SPDX-License-Identifier:	GPL-2.0+
>   */
>  
>  #ifndef _DMA_H_
>  #define _DMA_H_
>  
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +
>  /*
> - * enum dma_direction - dma transfer direction indicator
> + * enum dma_transfer_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 {
> +enum dma_transfer_direction {
>  	DMA_MEM_TO_MEM,
>  	DMA_MEM_TO_DEV,
>  	DMA_DEV_TO_MEM,
>  	DMA_DEV_TO_DEV,
>  };
>  
> -#define DMA_SUPPORTS_MEM_TO_MEM	BIT(0)
> -#define DMA_SUPPORTS_MEM_TO_DEV	BIT(1)
> -#define DMA_SUPPORTS_DEV_TO_MEM	BIT(2)
> -#define DMA_SUPPORTS_DEV_TO_DEV	BIT(3)
> +/**
> + * 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 provider. A provider will
> + * often implement multiple separate DMAs, since the hardware it manages
> + * often has this capability. dma_uclass.h describes the interface which
> + * DMA providers must implement.
> + * 
> + * DMA consumers/clients are the HW modules driven by the DMA channels. This
> + * header file describes the API used by drivers for those HW modules.
> + */
>  
> -/*
> - * struct dma_ops - Driver model DMA operations
> +struct udevice;
> +
> +/**
> + * struct dma - A handle to (allowing control of) a single DMA.
> + *
> + * Clients provide storage for DMA handles. The content of the structure is
> + * managed solely by the DMA API and DMA drivers. A DMA struct is
> + * initialized by "get"ing the DMA struct. The DMA struct is passed to all
> + * other DMA APIs to identify which DMA channel to operate upon.
>   *
> - * The uclass interface is implemented by all DMA devices which use
> - * driver model.
> + * @dev: The device which implements the DMA channel.
> + * @id: The DMA channel ID within the provider.
> + *
> + * Currently, the DMA API assumes that a single integer ID is enough to
> + * identify and configure any DMA channel for any DMA provider. If this
> + * assumption becomes invalid in the future, the struct could be expanded to
> + * either (a) add more fields to allow DMA providers to store additional
> + * information, or (b) replace the id field with an opaque pointer, which the
> + * provider would dynamically allocated during its .of_xlate op, and process
> + * during is .request op. This may require the addition of an extra op to clean
> + * up the allocation.
>   */
> -struct dma_ops {
> +struct dma {
> +	struct udevice *dev;
>  	/*
> -	 * 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
> +	 * Written by of_xlate. We assume a single id is enough for now. In the
> +	 * future, we might add more fields here.
>  	 */
> -	int (*transfer)(struct udevice *dev, int direction, void *dst,
> -			void *src, size_t len);
> +	unsigned long id;
>  };
>  
> -/*
> - * struct dma_dev_priv - information about a device used by the uclass
> +#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DMA)
> +struct phandle_2_cell;
> +int dma_get_by_index_platdata(struct udevice *dev, int index,
> +			      struct phandle_2_cell *cells, struct dma *dma);
> +
> +/**
> + * dma_get_by_index - Get/request a DMA by integer index.
> + *
> + * This looks up and requests a DMA. The index is relative to the client
> + * device; each device is assumed to have n DMAs associated with it somehow,
> + * and this function finds and requests one of them. The mapping of client
> + * device DMA indices to provider DMAs may be via device-tree properties,
> + * board-provided mapping tables, or some other mechanism.
>   *
> - * @supported: mode of transfers that DMA can support, should be
> - *	       one/multiple of DMA_SUPPORTS_*
> + * @dev:	The client device.
> + * @index:	The index of the DMA to request, within the client's list of
> + *		DMA channels.
> + * @dma:	A pointer to a DMA struct to initialize.
> + * @return 0 if OK, or a negative error code.
>   */
> -struct dma_dev_priv {
> -	u32 supported;
> -};
> +int dma_get_by_index(struct udevice *dev, int index, struct dma *dma);
>  
> -/*
> - * dma_get_device - get a DMA device which supports transfer
> - * type of transfer_type
> - *
> - * @transfer_type - transfer type should be one/multiple of
> - *		    DMA_SUPPORTS_*
> - * @devp - udevice pointer to return the found device
> - * @return - will return on success and devp will hold the
> - *	     pointer to the device
> +/**
> + * dma_get_by_name - Get/request a DMA by name.
> + *
> + * This looks up and requests a DMA. The name is relative to the client
> + * device; each device is assumed to have n DMAs associated with it somehow,
> + * and this function finds and requests one of them. The mapping of client
> + * device DMA names to provider DMAs may be via device-tree properties,
> + * board-provided mapping tables, or some other mechanism.
> + *
> + * @dev:	The client device.
> + * @name:	The name of the DMA to request, within the client's list of
> + *		DMA channels.
> + * @dma:	A pointer to a DMA struct to initialize.
> + * @return 0 if OK, or a negative error code.
>   */
> -int dma_get_device(u32 transfer_type, struct udevice **devp);
> +int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma);
> +#else
> +static inline int dma_get_by_index(struct udevice *dev, int index,
> +				   struct dma *dma)
> +{
> +	return -ENOSYS;
> +}
>  
> -/*
> - * dma_memcpy - try to use DMA to do a mem copy which will be
> - *		much faster than CPU mem copy
> - *
> - * @dst - destination pointer
> - * @src - souce pointer
> - * @len - data length to be copied
> - * @return - on successful transfer returns no of bytes
> -	     transferred and on failure return error code.
> +static inline int dma_get_by_name(struct udevice *dev, const char *name,
> +			   struct dma *dma)
> +{
> +	return -ENOSYS;
> +}
> +#endif
> +
> +/**
> + * dma_request - Request a DMA by provider-specific ID.
> + *
> + * This requests a DMA using a provider-specific ID. Generally, this function
> + * should not be used, since dma_get_by_index/name() provide an interface that
> + * better separates clients from intimate knowledge of DMA providers.
> + * However, this function may be useful in core SoC-specific code.
> + *
> + * @dev: The DMA provider device.
> + * @dma: A pointer to a DMA struct to initialize. The caller must
> + *	 have already initialized any field in this struct which the
> + *	 DMA provider uses to identify the DMA channel.
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_request(struct udevice *dev, struct dma *dma);
> +
> +/**
> + * dma_free - Free a previously requested DMA.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_free(struct dma *dma);
> +
> +/**
> + * dma_enable() - Enable (turn on) a DMA channel.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @return zero on success, or -ve error code.
> + */
> +int dma_enable(struct dma *dma);
> +
> +/**
> + * dma_disable() - Disable (turn off) a DMA channel.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @return zero on success, or -ve error code.
> + */
> +int dma_disable(struct dma *dma);
> +
> +/**
> + * dma_memcpy() - Try to use DMA to do a mem copy which will be much faster
> + *		  than CPU mem copy.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @dst: The destination pointer.
> + * @src: The source pointer.
> + * @len: Length of the data to be copied.
> + * @return zero on success, or -ve error code.
> + */
> +int dma_memcpy(struct dma *dma, void *dst, void *src, size_t len);
> +
> +/**
> + * dma_receive() - Receive a DMA transfer.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @dst: The destination pointer.
> + * @return zero on success, or -ve error code.
> + */
> +int dma_receive(struct dma *dma, void **dst);
> +
> +/**
> + * dma_send() - Send a DMA transfer.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @src: The source pointer.
> + * @len: Length of the data to be copied.
> + * @return zero on success, or -ve error code.
>   */
> -int dma_memcpy(void *dst, void *src, size_t len);
> +int dma_send(struct dma *dma, void *src, size_t len);
>  
> -#endif	/* _DMA_H_ */
> +#endif /* _DMA_H_ */
> diff --git a/include/spi_flash.h b/include/spi_flash.h
> index f3c4e83424..f31e8b8145 100644
> --- a/include/spi_flash.h
> +++ b/include/spi_flash.h
> @@ -65,6 +65,9 @@ struct spi_flash {
>  #ifdef CONFIG_DM_SPI_FLASH
>  	struct udevice *dev;
>  #endif
> +#ifdef CONFIG_DMA
> +	struct dma *dma;
> +#endif
>  	const char *name;
>  	u8 dual_flash;
>  	u8 shift;
> 

-- 
Regards
Vignesh

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 00/15] bmips: add bcm6348-enet support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (14 preceding siblings ...)
  2018-02-19 17:26 ` [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
@ 2018-02-20 17:46 ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
                     ` (14 more replies)
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (2 subsequent siblings)
  18 siblings, 15 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

In order to add bcm6348-enet support, dma-uclass must be extended to support
dma channels and reworked to operate like the other dm uclass (clk, reset...).

This is a RFC, so please give you feedback on the things that I should
fix or rework.

v2: Introduce changes reported by Vignesh:
 - Respect current dma implementation.
 - Let dma_memcpy find a compatible dma device.
Other changes:
 - Fix bcm6348-iudma rx burst config.

Álvaro Fernández Rojas (15):
  dma: move dma_ops to dma-uclass.h
  dma: add channels support
  dma: add bcm6348-iudma support
  bmips: bcm6338: add bcm6348-iudma support
  bmips: bcm6348: add bcm6348-iudma support
  bmips: bcm6358: add bcm6348-iudma support
  phy: add support for internal phys
  net: add support for bcm6348-enet
  bmips: bcm6338: add support for bcm6348-enet
  bmips: enable f at st1704 enet support
  bmips: bcm6348: add support for bcm6348-enet
  bmips: enable ct-5361 enet support
  bmips: bcm6358: add support for bcm6348-enet
  bmips: enable hg556a enet support
  bmips: enable nb4-ser enet support

 arch/mips/dts/brcm,bcm6338.dtsi       |  29 ++
 arch/mips/dts/brcm,bcm6348.dtsi       |  42 +++
 arch/mips/dts/brcm,bcm6358.dtsi       |  46 +++
 arch/mips/dts/comtrend,ct-5361.dts    |  12 +
 arch/mips/dts/huawei,hg556a.dts       |  12 +
 arch/mips/dts/sagem,f at st1704.dts      |  12 +
 arch/mips/dts/sfr,nb4-ser.dts         |  24 ++
 configs/comtrend_ct5361_ram_defconfig |   8 +-
 configs/huawei_hg556a_ram_defconfig   |   8 +-
 configs/sagem_f at st1704_ram_defconfig  |   9 +-
 configs/sfr_nb4-ser_ram_defconfig     |   8 +-
 drivers/dma/Kconfig                   |  16 ++
 drivers/dma/Makefile                  |   1 +
 drivers/dma/bcm6348-iudma.c           | 505 +++++++++++++++++++++++++++++++++
 drivers/dma/dma-uclass.c              | 180 +++++++++++-
 drivers/net/Kconfig                   |  10 +
 drivers/net/Makefile                  |   1 +
 drivers/net/bcm6348-eth.c             | 517 ++++++++++++++++++++++++++++++++++
 include/configs/bmips_common.h        |   5 +-
 include/dma-uclass.h                  | 115 ++++++++
 include/dma.h                         | 191 +++++++++++--
 include/dt-bindings/dma/bcm6338-dma.h |  15 +
 include/dt-bindings/dma/bcm6348-dma.h |  17 ++
 include/dt-bindings/dma/bcm6358-dma.h |  17 ++
 include/phy.h                         |   2 +
 25 files changed, 1774 insertions(+), 28 deletions(-)
 create mode 100644 drivers/dma/bcm6348-iudma.c
 create mode 100644 drivers/net/bcm6348-eth.c
 create mode 100644 include/dma-uclass.h
 create mode 100644 include/dt-bindings/dma/bcm6338-dma.h
 create mode 100644 include/dt-bindings/dma/bcm6348-dma.h
 create mode 100644 include/dt-bindings/dma/bcm6358-dma.h

-- 
2.11.0

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 01/15] dma: move dma_ops to dma-uclass.h
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 18:49     ` Simon Glass
  2018-02-20 17:46   ` [U-Boot] [RFC v2 02/15] dma: add channels support Álvaro Fernández Rojas
                     ` (13 subsequent siblings)
  14 siblings, 1 reply; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Move dma_ops to a separate header file, following other uclass implementations.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 drivers/dma/dma-uclass.c |  3 ++-
 include/dma-uclass.h     | 38 ++++++++++++++++++++++++++++++++++++++
 include/dma.h            | 22 ----------------------
 3 files changed, 40 insertions(+), 23 deletions(-)
 create mode 100644 include/dma-uclass.h

diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
index 3d0ce22fbc..6fd4e1b35d 100644
--- a/drivers/dma/dma-uclass.c
+++ b/drivers/dma/dma-uclass.c
@@ -10,10 +10,11 @@
  */
 
 #include <common.h>
-#include <dma.h>
 #include <dm.h>
 #include <dm/uclass-internal.h>
 #include <dm/device-internal.h>
+#include <dma.h>
+#include <dma-uclass.h>
 #include <errno.h>
 
 DECLARE_GLOBAL_DATA_PTR;
diff --git a/include/dma-uclass.h b/include/dma-uclass.h
new file mode 100644
index 0000000000..e29ad103f2
--- /dev/null
+++ b/include/dma-uclass.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated, <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DMA_UCLASS_H
+#define _DMA_UCLASS_H
+
+/* See dma.h for background documentation. */
+
+#include <dma.h>
+
+/*
+ * 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);
+};
+
+#endif /* _DMA_UCLASS_H */
diff --git a/include/dma.h b/include/dma.h
index 71fa77f2ea..89320f10d9 100644
--- a/include/dma.h
+++ b/include/dma.h
@@ -28,28 +28,6 @@ enum dma_direction {
 #define DMA_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, should be
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 02/15] dma: add channels support
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 18:49     ` Simon Glass
  2018-02-20 17:46   ` [U-Boot] [RFC v2 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
                     ` (12 subsequent siblings)
  14 siblings, 1 reply; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

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 <noltari@gmail.com>
---
 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 <dm/device-internal.h>
 #include <dma.h>
 #include <dma-uclass.h>
+#include <dt-structs.h>
 #include <errno.h>
 
 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);
+	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);
+	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 <dma.h>
+#include <fdtdec.h>
 
 /*
  * 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);
+	/**
+	 * request - Request a translated DMA.
+	 *
+	 * The DMA core calls this function as the second step in
+	 * implementing a client's dma_get_by_*() call, following a successful
+	 * xxx_xlate() call, or as the only step in implementing a client's
+	 * dma_request() call.
+	 *
+	 * @dma: The DMA struct to request; this has been filled in by
+	 *   a previoux xxx_xlate() function call, or by the caller of
+	 *   dma_request().
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*request)(struct dma *dma);
+	/**
+	 * free - Free a previously requested dma.
+	 *
+	 * This is the implementation of the client dma_free() API.
+	 *
+	 * @dma: The DMA to free.
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*free)(struct dma *dma);
+	/**
+	 * enable() - Enable a DMA Channel.
+	 *
+	 * @dma: The DMA Channel to manipulate.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*enable)(struct dma *dma);
+	/**
+	 * disable() - Disable a DMA Channel.
+	 *
+	 * @dma: The DMA Channel to manipulate.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*disable)(struct dma *dma);
+	/**
+	 * 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 copied.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*send)(struct dma *dma, void *src, size_t len);
+#endif /* CONFIG_DMA_CHANNELS */
 	/*
 	 * Get the current timer count
 	 *
diff --git a/include/dma.h b/include/dma.h
index 89320f10d9..d9d8567b93 100644
--- a/include/dma.h
+++ b/include/dma.h
@@ -8,6 +8,9 @@
 #ifndef _DMA_H_
 #define _DMA_H_
 
+#include <linux/errno.h>
+#include <linux/types.h>
+
 /*
  * enum dma_direction - dma transfer direction indicator
  * @DMA_MEM_TO_MEM: Memcpy mode
@@ -37,6 +40,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 provider. A provider will
+ * often implement multiple separate DMAs, since the hardware it manages
+ * often has this capability. dma_uclass.h describes the interface which
+ * DMA providers must implement.
+ *
+ * DMA consumers/clients are the HW modules driven by the DMA channels. This
+ * header file describes the API used by drivers for those HW modules.
+ */
+
+struct udevice;
+
+/**
+ * struct dma - A handle to (allowing control of) a single DMA.
+ *
+ * Clients provide storage for DMA handles. The content of the structure is
+ * managed solely by the DMA API and DMA drivers. A DMA struct is
+ * initialized by "get"ing the DMA struct. The DMA struct is passed to all
+ * other DMA APIs to identify which DMA channel to operate upon.
+ *
+ * @dev: The device which implements the DMA channel.
+ * @id: The DMA channel ID within the provider.
+ *
+ * Currently, the DMA API assumes that a single integer ID is enough to
+ * identify and configure any DMA channel for any DMA provider. If this
+ * assumption becomes invalid in the future, the struct could be expanded to
+ * either (a) add more fields to allow DMA providers to store additional
+ * information, or (b) replace the id field with an opaque pointer, which the
+ * provider would dynamically allocated during its .of_xlate op, and process
+ * during is .request op. This may require the addition of an extra op to clean
+ * up the allocation.
+ */
+struct dma {
+	struct udevice *dev;
+	/*
+	 * Written by of_xlate. We assume a single id is enough for now. In the
+	 * future, we might add more fields here.
+	 */
+	unsigned long id;
+};
+
+# if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DMA)
+struct phandle_2_cell;
+int dma_get_by_index_platdata(struct udevice *dev, int index,
+			      struct phandle_2_cell *cells, struct dma *dma);
+
+/**
+ * dma_get_by_index - Get/request a DMA by integer index.
+ *
+ * This looks up and requests a DMA. The index is relative to the client
+ * device; each device is assumed to have n DMAs associated with it somehow,
+ * and this function finds and requests one of them. The mapping of client
+ * device DMA indices to provider DMAs may be via device-tree properties,
+ * board-provided mapping tables, or some other mechanism.
+ *
+ * @dev:	The client device.
+ * @index:	The index of the DMA to request, within the client's list of
+ *		DMA channels.
+ * @dma:	A pointer to a DMA struct to initialize.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_get_by_index(struct udevice *dev, int index, struct dma *dma);
+
+/**
+ * dma_get_by_name - Get/request a DMA by name.
+ *
+ * This looks up and requests a DMA. The name is relative to the client
+ * device; each device is assumed to have n DMAs associated with it somehow,
+ * and this function finds and requests one of them. The mapping of client
+ * device DMA names to provider DMAs may be via device-tree properties,
+ * board-provided mapping tables, or some other mechanism.
+ *
+ * @dev:	The client device.
+ * @name:	The name of the DMA to request, within the client's list of
+ *		DMA channels.
+ * @dma:	A pointer to a DMA struct to initialize.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma);
+# else
+static inline int dma_get_by_index(struct udevice *dev, int index,
+				   struct dma *dma)
+{
+	return -ENOSYS;
+}
+
+static inline int dma_get_by_name(struct udevice *dev, const char *name,
+			   struct dma *dma)
+{
+	return -ENOSYS;
+}
+# endif
+
+/**
+ * dma_request - Request a DMA by provider-specific ID.
+ *
+ * This requests a DMA using a provider-specific ID. Generally, this function
+ * should not be used, since dma_get_by_index/name() provide an interface that
+ * better separates clients from intimate knowledge of DMA providers.
+ * However, this function may be useful in core SoC-specific code.
+ *
+ * @dev: The DMA provider device.
+ * @dma: A pointer to a DMA struct to initialize. The caller must
+ *	 have already initialized any field in this struct which the
+ *	 DMA provider uses to identify the DMA channel.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_request(struct udevice *dev, struct dma *dma);
+
+/**
+ * dma_free - Free a previously requested DMA.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_free(struct dma *dma);
+
+/**
+ * dma_enable() - Enable (turn on) a DMA channel.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return zero on success, or -ve error code.
+ */
+int dma_enable(struct dma *dma);
+
+/**
+ * dma_disable() - Disable (turn off) a DMA channel.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return zero on success, or -ve error code.
+ */
+int dma_disable(struct dma *dma);
+
+/**
+ * dma_receive() - Receive a DMA transfer.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @dst: The destination pointer.
+ * @return zero on success, or -ve error code.
+ */
+int dma_receive(struct dma *dma, void **dst);
+
+/**
+ * dma_send() - Send a DMA transfer.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @src: The source pointer.
+ * @len: Length of the data to be copied.
+ * @return zero on success, or -ve error code.
+ */
+int dma_send(struct dma *dma, void *src, size_t len);
+#endif /* CONFIG_DMA_CHANNELS */
+
 /*
  * dma_get_device - get a DMA device which supports transfer
  * type of transfer_type
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 03/15] dma: add bcm6348-iudma support
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 02/15] dma: add channels support Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 04/15] bmips: bcm6338: " Álvaro Fernández Rojas
                     ` (11 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

BCM6348 IUDMA controller is present on multiple BMIPS (BCM63xx) SoCs.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: Fix dma rx burst config and select DMA_CHANNELS.

 drivers/dma/Kconfig         |   9 +
 drivers/dma/Makefile        |   1 +
 drivers/dma/bcm6348-iudma.c | 505 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 515 insertions(+)
 create mode 100644 drivers/dma/bcm6348-iudma.c

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 21b2c0dcaa..9afa158b51 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -19,6 +19,15 @@ config DMA_CHANNELS
 	  Enable channels support for DMA. Some DMA controllers have multiple
 	  channels which can either transfer data to/from different devices.
 
+config BCM6348_IUDMA
+	bool "BCM6348 IUDMA driver"
+	depends on ARCH_BMIPS
+	select DMA_CHANNELS
+	help
+	  Enable the BCM6348 IUDMA driver.
+	  This driver support data transfer from devices to
+	  memory and from memory to devices.
+
 config TI_EDMA3
 	bool "TI EDMA3 driver"
 	help
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 39b78b2a3d..b2b4147349 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_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_BCM6348_IUDMA) += bcm6348-iudma.o
 obj-$(CONFIG_FSL_DMA) += fsl_dma.o
 obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
 obj-$(CONFIG_TI_EDMA3) += ti-edma3.o
diff --git a/drivers/dma/bcm6348-iudma.c b/drivers/dma/bcm6348-iudma.c
new file mode 100644
index 0000000000..8016a58be2
--- /dev/null
+++ b/drivers/dma/bcm6348-iudma.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/dma/bcm63xx-iudma.c:
+ *	Copyright (C) 2015 Simon Arlott <simon@fire.lp0.eu>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
+ *	Copyright (C) 2000-2010 Broadcom Corporation
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/bcmdrivers/opensource/net/enet/impl4/bcmenet.c:
+ *	Copyright (C) 2010 Broadcom Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma-uclass.h>
+#include <memalign.h>
+#include <net.h>
+#include <reset.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ALIGN_END_ADDR(type, ptr, size)	\
+	((unsigned long)(ptr) + roundup((size) * sizeof(type), \
+	 ARCH_DMA_MINALIGN))
+
+/* DMA Channels */
+#define DMA_CHAN_FLOWC(x)		((x) >> 1)
+#define DMA_CHAN_FLOWC_MAX		8
+#define DMA_CHAN_MAX			16
+#define DMA_CHAN_SIZE			0x10
+#define DMA_CHAN_TOUT			500
+
+/* DMA Global Configuration register */
+#define DMA_CFG_REG			0x00
+#define DMA_CFG_ENABLE_SHIFT		0
+#define DMA_CFG_ENABLE_MASK		(1 << DMA_CFG_ENABLE_SHIFT)
+#define DMA_CFG_FLOWC_ENABLE(x)		BIT(DMA_CHAN_FLOWC(x) + 1)
+#define DMA_CFG_NCHANS_SHIFT		24
+#define DMA_CFG_NCHANS_MASK		(0xf << DMA_CFG_NCHANS_SHIFT)
+
+/* DMA Global Flow Control Threshold registers */
+#define DMA_FLOWC_THR_LO_REG(x)		(0x04 + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_THR_LO_SHIFT		0
+#define DMA_FLOWC_THR_LO_MASK		(5 << DMA_FLOWC_THR_LO_SHIFT)
+
+#define DMA_FLOWC_THR_HI_REG(x)		(0x08 + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_THR_HI_SHIFT		0
+#define DMA_FLOWC_THR_HI_MASK		(10 << DMA_FLOWC_THR_HI_SHIFT)
+
+/* DMA Global Flow Control Buffer Allocation registers */
+#define DMA_FLOWC_ALLOC_REG(x)		(0x0c + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_ALLOC_FORCE_SHIFT	31
+#define DMA_FLOWC_ALLOC_FORCE_MASK	(1 << DMA_FLOWC_ALLOC_FORCE_SHIFT)
+
+/* DMA Global Reset register */
+#define DMA_RST_REG			0x34
+#define DMA_RST_CHAN_SHIFT		0
+#define DMA_RST_CHAN_MASK(x)		(1 << x)
+
+/* DMA Channel Configuration register */
+#define DMAC_CFG_REG(x)			(DMA_CHAN_SIZE * (x) + 0x00)
+#define DMAC_CFG_ENABLE_SHIFT		0
+#define DMAC_CFG_ENABLE_MASK		(1 << DMAC_CFG_ENABLE_SHIFT)
+#define DMAC_CFG_PKT_HALT_SHIFT		1
+#define DMAC_CFG_PKT_HALT_MASK		(1 << DMAC_CFG_PKT_HALT_SHIFT)
+#define DMAC_CFG_BRST_HALT_SHIFT	2
+#define DMAC_CFG_BRST_HALT_MASK		(1 << DMAC_CFG_BRST_HALT_SHIFT)
+
+/* DMA Channel Interrupts registers */
+#define DMAC_IR_ST_REG(x)		(DMA_CHAN_SIZE * (x) + 0x04)
+#define DMAC_IR_EN_REG(x)		(DMA_CHAN_SIZE * (x) + 0x08)
+
+#define DMAC_IR_DONE_SHIFT		2
+#define DMAC_IR_DONE_MASK		(1 << DMAC_IR_DONE_SHIFT)
+
+/* DMA Channel Max Burst Length register */
+#define DMAC_BURST_REG(x)		(DMA_CHAN_SIZE * (x) + 0x0c)
+#define DMAC_BURST_MAX_SHIFT		0
+#define DMAC_BURST_MAX_MASK		(16 << DMAC_BURST_MAX_SHIFT)
+
+/* DMA SRAM Descriptor Ring Start register */
+#define DMAS_RSTART_REG(x)		(DMA_CHAN_SIZE * (x) + 0x00)
+
+/* DMA SRAM State/Bytes done/ring offset register */
+#define DMAS_STATE_DATA_REG(x)		(DMA_CHAN_SIZE * (x) + 0x04)
+
+/* DMA SRAM Buffer Descriptor status and length register */
+#define DMAS_DESC_LEN_STATUS_REG(x)	(DMA_CHAN_SIZE * (x) + 0x08)
+
+/* DMA SRAM Buffer Descriptor status and length register */
+#define DMAS_DESC_BASE_BUFPTR_REG(x)	(DMA_CHAN_SIZE * (x) + 0x0c)
+
+struct bcm6348_dma_desc {
+	uint16_t length;
+
+	uint16_t status;
+#define DMAD_ST_CRC_SHIFT	8
+#define DMAD_ST_CRC_MASK	(1 << DMAD_ST_CRC_SHIFT)
+#define DMAD_ST_WRAP_SHIFT	12
+#define DMAD_ST_WRAP_MASK	(1 << DMAD_ST_WRAP_SHIFT)
+#define DMAD_ST_SOP_SHIFT	13
+#define DMAD_ST_SOP_MASK	(1 << DMAD_ST_SOP_SHIFT)
+#define DMAD_ST_EOP_SHIFT	14
+#define DMAD_ST_EOP_MASK	(1 << DMAD_ST_EOP_SHIFT)
+#define DMAD_ST_OWN_SHIFT	15
+#define DMAD_ST_OWN_MASK	(1 << DMAD_ST_OWN_SHIFT)
+
+	uint32_t address;
+} __attribute__((aligned(1)));
+
+struct bcm6348_chan_priv {
+	void __iomem *dma_ring;
+	uint8_t dma_ring_size;
+	uint8_t desc_id;
+};
+
+struct bcm6348_iudma_priv {
+	void __iomem *base;
+	void __iomem *chan;
+	void __iomem *sram;
+	struct bcm6348_chan_priv **ch_priv;
+	uint8_t n_channels;
+};
+
+static bool bcm6348_iudma_chan_is_rx(uint8_t ch)
+{
+	return !(ch & 1);
+}
+
+static void bcm6348_iudma_chan_stop(struct bcm6348_iudma_priv *priv,
+				    uint8_t ch)
+{
+	unsigned int timeout = DMA_CHAN_TOUT;
+
+	/* disable dma channel interrupts */
+	writel_be(0, priv->chan + DMAC_IR_EN_REG(ch));
+
+	do {
+		uint32_t cfg, halt;
+
+		if (timeout > DMA_CHAN_TOUT / 2)
+			halt = DMAC_CFG_PKT_HALT_MASK;
+		else
+			halt = DMAC_CFG_BRST_HALT_MASK;
+
+		/* try to stop dma channel */
+		writel_be(halt, priv->chan + DMAC_CFG_REG(ch));
+		mb();
+
+		/* check if channel was stopped */
+		cfg = readl_be(priv->chan + DMAC_CFG_REG(ch));
+		if (!(cfg & DMAC_CFG_ENABLE_MASK))
+			break;
+
+		udelay(1);
+	} while (--timeout);
+
+	if (!timeout)
+		pr_err("unable to stop channel %u\n", ch);
+
+	/* reset dma channel */
+	setbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
+	clrbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
+}
+
+static int bcm6348_iudma_disable(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+
+	bcm6348_iudma_chan_stop(priv, dma->id);
+
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		writel_be(DMA_FLOWC_ALLOC_FORCE_MASK,
+			  DMA_FLOWC_ALLOC_REG(dma->id));
+
+	return 0;
+}
+
+static int bcm6348_iudma_enable(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	uint8_t i;
+
+	/* init dma rings */
+	dma_desc = ch_priv->dma_ring;
+	for (i = 0; i < ch_priv->dma_ring_size; i++) {
+		if (bcm6348_iudma_chan_is_rx(dma->id)) {
+			dma_desc->status = DMAD_ST_OWN_MASK;
+			dma_desc->length = PKTSIZE_ALIGN;
+			dma_desc->address = virt_to_phys(net_rx_packets[i]);
+		} else {
+			dma_desc->status = 0;
+			dma_desc->length = 0;
+			dma_desc->address = 0;
+		}
+
+		if (i == ch_priv->dma_ring_size - 1)
+			dma_desc->status |= DMAD_ST_WRAP_MASK;
+
+		if (bcm6348_iudma_chan_is_rx(dma->id))
+			writel_be(1,
+				  priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
+
+		dma_desc++;
+	}
+
+	/* init to first descriptor */
+	ch_priv->desc_id = 0;
+
+	/* force cache writeback */
+	flush_dcache_range((ulong)ch_priv->dma_ring,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, ch_priv->dma_ring,
+			       ch_priv->dma_ring_size));
+
+	/* clear sram */
+	writel_be(0, priv->sram + DMAS_STATE_DATA_REG(dma->id));
+	writel_be(0, priv->sram + DMAS_DESC_LEN_STATUS_REG(dma->id));
+	writel_be(0, priv->sram + DMAS_DESC_BASE_BUFPTR_REG(dma->id));
+
+	/* set dma ring start */
+	writel_be(virt_to_phys(ch_priv->dma_ring),
+		  priv->sram + DMAS_RSTART_REG(dma->id));
+
+	/* set flow control */
+	if (bcm6348_iudma_chan_is_rx(dma->id)) {
+		u32 val;
+
+		setbits_be32(priv->base + DMA_CFG_REG,
+			     DMA_CFG_FLOWC_ENABLE(dma->id));
+
+		val = ch_priv->dma_ring_size / 3;
+		writel_be(val, priv->base + DMA_FLOWC_THR_LO_REG(dma->id));
+
+		val = (ch_priv->dma_ring_size * 2) / 3;
+		writel_be(val, priv->base + DMA_FLOWC_THR_HI_REG(dma->id));
+	}
+
+	/* set dma max burst */
+	writel_be(ch_priv->dma_ring_size,
+		  priv->chan + DMAC_BURST_REG(dma->id));
+
+	/* clear interrupts */
+	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_ST_REG(dma->id));
+	writel_be(0, priv->chan + DMAC_IR_EN_REG(dma->id));
+
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	return 0;
+}
+
+static int bcm6348_iudma_request(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv;
+
+	/* check if channel is valid */
+	if (dma->id >= priv->n_channels)
+		return -ENODEV;
+
+	/* alloc channel private data */
+	priv->ch_priv[dma->id] = calloc(1, sizeof(struct bcm6348_chan_priv));
+	if (!priv->ch_priv[dma->id])
+		return -ENOMEM;
+	ch_priv = priv->ch_priv[dma->id];
+
+	/* alloc dma ring */
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		ch_priv->dma_ring_size = PKTBUFSRX;
+	else
+		ch_priv->dma_ring_size = 1;
+	ch_priv->dma_ring =
+		malloc_cache_aligned(sizeof(struct bcm6348_dma_desc) *
+				     ch_priv->dma_ring_size);
+	if (!ch_priv->dma_ring)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int bcm6348_iudma_receive(struct dma *dma, void **dst)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	void __iomem *dma_buff;
+	uint16_t status;
+	int ret;
+
+	/* get dma ring descriptor address */
+	dma_desc = ch_priv->dma_ring;
+	dma_desc += ch_priv->desc_id;
+
+	/* invalidate cache data */
+	invalidate_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* check dma own */
+	if (dma_desc->status & DMAD_ST_OWN_MASK)
+		return 0;
+
+	/* check dma end */
+	if (!(dma_desc->status & DMAD_ST_EOP_MASK))
+		return -EINVAL;
+
+	/* get dma buff descriptor address */
+	dma_buff = phys_to_virt(dma_desc->address);
+
+	/* invalidate cache data */
+	invalidate_dcache_range((ulong)dma_buff,
+				(ulong)(dma_buff + PKTSIZE_ALIGN));
+
+	/* get dma data */
+	*dst = dma_buff;
+	ret = dma_desc->length;
+
+	/* reinit dma descriptor */
+	status = dma_desc->status & DMAD_ST_WRAP_MASK;
+	status |= DMAD_ST_OWN_MASK;
+
+	dma_desc->length = PKTSIZE_ALIGN;
+	dma_desc->status = status;
+
+	/* flush cache */
+	flush_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* set flow control buffer alloc */
+	writel_be(1, priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
+
+	/* enable dma */
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	/* set interrupt */
+	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_EN_REG(dma->id));
+
+	/* increment dma descriptor */
+	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->dma_ring_size;
+
+	return ret - 4;
+}
+
+static int bcm6348_iudma_send(struct dma *dma, void *src, size_t len)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	uint16_t val;
+
+	/* get dma ring descriptor address */
+	dma_desc = ch_priv->dma_ring;
+	dma_desc += ch_priv->desc_id;
+
+	dma_desc->address = virt_to_phys(src);
+
+	/* config dma descriptor */
+	val = (DMAD_ST_OWN_MASK |
+	       DMAD_ST_EOP_MASK |
+	       DMAD_ST_CRC_MASK |
+	       DMAD_ST_SOP_MASK);
+	if (ch_priv->desc_id == ch_priv->dma_ring_size - 1)
+		val |= DMAD_ST_WRAP_MASK;
+
+	dma_desc->length = len;
+	dma_desc->status = val;
+
+	/* flush cache */
+	flush_dcache_range((ulong)src, (ulong)src + PKTSIZE_ALIGN);
+
+	/* flush cache */
+	flush_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* enable dma */
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	/* set interrupt */
+	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_EN_REG(dma->id));
+
+	/* poll dma status */
+	do {
+		/* invalidate cache */
+		invalidate_dcache_range((ulong)dma_desc,
+			ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+		if (!(dma_desc->status & DMAD_ST_OWN_MASK))
+			break;
+	} while(1);
+
+	/* increment dma descriptor */
+	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->dma_ring_size;
+
+	return 0;
+}
+
+static const struct dma_ops bcm6348_iudma_ops = {
+	.disable = bcm6348_iudma_disable,
+	.enable = bcm6348_iudma_enable,
+	.request = bcm6348_iudma_request,
+	.receive = bcm6348_iudma_receive,
+	.send = bcm6348_iudma_send,
+};
+
+static const struct udevice_id bcm6348_iudma_ids[] = {
+	{ .compatible = "brcm,bcm6348-iudma", },
+	{ /* sentinel */ }
+};
+
+static int bcm6348_iudma_probe(struct udevice *dev)
+{
+	struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+	uint8_t ch;
+	int i;
+
+	uc_priv->supported = DMA_SUPPORTS_DEV_TO_MEM |
+			     DMA_SUPPORTS_MEM_TO_DEV;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+		if (clk_enable(&clk))
+			pr_err("failed to enable clock %d\n", i);
+		clk_free(&clk);
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+		if (reset_deassert(&reset))
+			pr_err("failed to deassert reset %d\n", i);
+		reset_free(&reset);
+	}
+
+	/* dma global base address */
+	addr = devfdt_get_addr_name(dev, "dma");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->base = ioremap(addr, 0);
+
+	/* dma channels base address */
+	addr = devfdt_get_addr_name(dev, "dma-channels");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->chan = ioremap(addr, 0);
+
+	/* dma sram base address */
+	addr = devfdt_get_addr_name(dev, "dma-sram");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->sram = ioremap(addr, 0);
+
+	/* disable dma controller */
+	clrbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
+
+	/* get number of channels */
+	priv->n_channels = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+					   "dma-channels", 8);
+	if (priv->n_channels > DMA_CHAN_MAX)
+		return -EINVAL;
+
+	/* alloc channel private data pointers */
+	priv->ch_priv = calloc(priv->n_channels,
+			       sizeof(struct bcm6348_chan_priv*));
+	if (!priv->ch_priv)
+		return -ENOMEM;
+
+	/* stop dma channels */
+	for (ch = 0; ch < priv->n_channels; ch++)
+		bcm6348_iudma_chan_stop(priv, ch);
+
+	/* enable dma controller */
+	setbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_iudma) = {
+	.name = "bcm6348_iudma",
+	.id = UCLASS_DMA,
+	.of_match = bcm6348_iudma_ids,
+	.ops = &bcm6348_iudma_ops,
+	.priv_auto_alloc_size = sizeof(struct bcm6348_iudma_priv),
+	.probe = bcm6348_iudma_probe,
+};
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 04/15] bmips: bcm6338: add bcm6348-iudma support
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                     ` (2 preceding siblings ...)
  2018-02-20 17:46   ` [U-Boot] [RFC v2 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 05/15] bmips: bcm6348: " Álvaro Fernández Rojas
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: no changes

 arch/mips/dts/brcm,bcm6338.dtsi       | 14 ++++++++++++++
 include/dt-bindings/dma/bcm6338-dma.h | 15 +++++++++++++++
 2 files changed, 29 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6338-dma.h

diff --git a/arch/mips/dts/brcm,bcm6338.dtsi b/arch/mips/dts/brcm,bcm6338.dtsi
index 0cab44cb8d..4125f71d9f 100644
--- a/arch/mips/dts/brcm,bcm6338.dtsi
+++ b/arch/mips/dts/brcm,bcm6338.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6338-clock.h>
+#include <dt-bindings/dma/bcm6338-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6338-reset.h>
 #include "skeleton.dtsi"
@@ -131,5 +132,18 @@
 			reg = <0xfffe3100 0x38>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller at fffe2400 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe2400 0x1c>,
+			      <0xfffe2500 0x60>,
+			      <0xfffe2600 0x60>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <6>;
+			resets = <&periph_rst BCM6338_RST_DMAMEM>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6338-dma.h b/include/dt-bindings/dma/bcm6338-dma.h
new file mode 100644
index 0000000000..5dd66239b4
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6338-dma.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6338_H
+#define __DT_BINDINGS_DMA_BCM6338_H
+
+#define BCM6338_DMA_ENET_RX	0
+#define BCM6338_DMA_ENET_TX	1
+
+#endif /* __DT_BINDINGS_DMA_BCM6338_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 05/15] bmips: bcm6348: add bcm6348-iudma support
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                     ` (3 preceding siblings ...)
  2018-02-20 17:46   ` [U-Boot] [RFC v2 04/15] bmips: bcm6338: " Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 06/15] bmips: bcm6358: " Álvaro Fernández Rojas
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: no changes

 arch/mips/dts/brcm,bcm6348.dtsi       | 16 ++++++++++++++++
 include/dt-bindings/dma/bcm6348-dma.h | 17 +++++++++++++++++
 2 files changed, 33 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6348-dma.h

diff --git a/arch/mips/dts/brcm,bcm6348.dtsi b/arch/mips/dts/brcm,bcm6348.dtsi
index 92fb91afc1..d774c59665 100644
--- a/arch/mips/dts/brcm,bcm6348.dtsi
+++ b/arch/mips/dts/brcm,bcm6348.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6348-clock.h>
+#include <dt-bindings/dma/bcm6348-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6348-reset.h>
 #include "skeleton.dtsi"
@@ -160,5 +161,20 @@
 			reg = <0xfffe2300 0x38>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller at fffe7000 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe7000 0x1c>,
+			      <0xfffe7100 0x40>,
+			      <0xfffe7200 0x40>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <4>;
+			clocks = <&periph_clk BCM6348_CLK_ENET>;
+			resets = <&periph_rst BCM6348_RST_ENET>,
+				 <&periph_rst BCM6348_RST_DMAMEM>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6348-dma.h b/include/dt-bindings/dma/bcm6348-dma.h
new file mode 100644
index 0000000000..a1d3a6456d
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6348-dma.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6348_H
+#define __DT_BINDINGS_DMA_BCM6348_H
+
+#define BCM6348_DMA_ENET0_RX	0
+#define BCM6348_DMA_ENET0_TX	1
+#define BCM6348_DMA_ENET1_RX	2
+#define BCM6348_DMA_ENET1_TX	3
+
+#endif /* __DT_BINDINGS_DMA_BCM6348_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 06/15] bmips: bcm6358: add bcm6348-iudma support
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                     ` (4 preceding siblings ...)
  2018-02-20 17:46   ` [U-Boot] [RFC v2 05/15] bmips: bcm6348: " Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 07/15] phy: add support for internal phys Álvaro Fernández Rojas
                     ` (8 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: no changes

 arch/mips/dts/brcm,bcm6358.dtsi       | 18 ++++++++++++++++++
 include/dt-bindings/dma/bcm6358-dma.h | 17 +++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6358-dma.h

diff --git a/arch/mips/dts/brcm,bcm6358.dtsi b/arch/mips/dts/brcm,bcm6358.dtsi
index b63b53baee..1468e4f63a 100644
--- a/arch/mips/dts/brcm,bcm6358.dtsi
+++ b/arch/mips/dts/brcm,bcm6358.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6358-clock.h>
+#include <dt-bindings/dma/bcm6358-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6358-reset.h>
 #include "skeleton.dtsi"
@@ -191,5 +192,22 @@
 
 			status = "disabled";
 		};
+
+		iudma: dma-controller at fffe5000 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe5000 0x24>,
+			      <0xfffe5100 0x80>,
+			      <0xfffe5200 0x80>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <8>;
+			clocks = <&periph_clk BCM6358_CLK_EMUSB>,
+				 <&periph_clk BCM6358_CLK_USBSU>,
+				 <&periph_clk BCM6358_CLK_EPHY>;
+			resets = <&periph_rst BCM6358_RST_ENET>,
+				 <&periph_rst BCM6358_RST_EPHY>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6358-dma.h b/include/dt-bindings/dma/bcm6358-dma.h
new file mode 100644
index 0000000000..3b1fcf8540
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6358-dma.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6358_H
+#define __DT_BINDINGS_DMA_BCM6358_H
+
+#define BCM6358_DMA_ENET0_RX	0
+#define BCM6358_DMA_ENET0_TX	1
+#define BCM6358_DMA_ENET1_RX	2
+#define BCM6358_DMA_ENET1_TX	3
+
+#endif /* __DT_BINDINGS_DMA_BCM6358_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 07/15] phy: add support for internal phys
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                     ` (5 preceding siblings ...)
  2018-02-20 17:46   ` [U-Boot] [RFC v2 06/15] bmips: bcm6358: " Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
                     ` (7 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: no changes

 include/phy.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/phy.h b/include/phy.h
index 0543ec10c2..8f3e53db01 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -50,6 +50,7 @@
 
 
 typedef enum {
+	PHY_INTERFACE_MODE_INTERNAL,
 	PHY_INTERFACE_MODE_MII,
 	PHY_INTERFACE_MODE_GMII,
 	PHY_INTERFACE_MODE_SGMII,
@@ -72,6 +73,7 @@ typedef enum {
 } phy_interface_t;
 
 static const char *phy_interface_strings[] = {
+	[PHY_INTERFACE_MODE_INTERNAL]		= "internal",
 	[PHY_INTERFACE_MODE_MII]		= "mii",
 	[PHY_INTERFACE_MODE_GMII]		= "gmii",
 	[PHY_INTERFACE_MODE_SGMII]		= "sgmii",
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 08/15] net: add support for bcm6348-enet
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                     ` (6 preceding siblings ...)
  2018-02-20 17:46   ` [U-Boot] [RFC v2 07/15] phy: add support for internal phys Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 09/15] bmips: bcm6338: " Álvaro Fernández Rojas
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: select DMA_CHANNELS.

 drivers/net/Kconfig            |  10 +
 drivers/net/Makefile           |   1 +
 drivers/net/bcm6348-eth.c      | 517 +++++++++++++++++++++++++++++++++++++++++
 include/configs/bmips_common.h |   5 +-
 4 files changed, 532 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/bcm6348-eth.c

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index de1947ccc1..e532332d78 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -71,6 +71,16 @@ config BCM_SF2_ETH_GMAC
 	  by the BCM_SF2_ETH driver.
 	  Say Y to any bcmcygnus based platforms.
 
+config BCM6348_ETH
+	bool "BCM6348 EMAC support"
+	depends on DM_ETH && ARCH_BMIPS
+	select DMA
+	select DMA_CHANNELS
+	select MII
+	select PHYLIB
+	help
+	  This driver supports the BCM6348 Ethernet MAC.
+
 config DWC_ETH_QOS
 	bool "Synopsys DWC Ethernet QOS device support"
 	depends on DM_ETH
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index ac5443c752..282adbc775 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
 obj-$(CONFIG_AG7XXX) += ag7xxx.o
 obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
+obj-$(CONFIG_BCM6348_ETH) += bcm6348-eth.o
 obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
 obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
 obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
diff --git a/drivers/net/bcm6348-eth.c b/drivers/net/bcm6348-eth.c
new file mode 100644
index 0000000000..890b7d5396
--- /dev/null
+++ b/drivers/net/bcm6348-eth.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma.h>
+#include <miiphy.h>
+#include <net.h>
+#include <phy.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+
+#define ETH_ZLEN			60
+
+#define ETH_TX_WATERMARK		32
+#define ETH_MAX_MTU_SIZE		1518
+
+#define ETH_TIMEOUT			100
+
+/* ETH Receiver Configuration register */
+#define ETH_RXCFG_REG			0x00
+#define ETH_RXCFG_ENFLOW_SHIFT		5
+#define ETH_RXCFG_ENFLOW_MASK		(1 << ETH_RXCFG_ENFLOW_SHIFT)
+
+/* ETH Receive Maximum Length register */
+#define ETH_RXMAXLEN_REG		0x04
+#define ETH_RXMAXLEN_SHIFT		0
+#define ETH_RXMAXLEN_MASK		(0x7ff << ETH_RXMAXLEN_SHIFT)
+
+/* ETH Transmit Maximum Length register */
+#define ETH_TXMAXLEN_REG		0x08
+#define ETH_TXMAXLEN_SHIFT		0
+#define ETH_TXMAXLEN_MASK		(0x7ff << ETH_TXMAXLEN_SHIFT)
+
+/* MII Status/Control register */
+#define MII_SC_REG			0x10
+#define MII_SC_MDCFREQDIV_SHIFT		0
+#define MII_SC_MDCFREQDIV_MASK		(0x7f << MII_SC_MDCFREQDIV_SHIFT)
+#define MII_SC_PREAMBLE_EN_SHIFT	7
+#define MII_SC_PREAMBLE_EN_MASK		(1 << MII_SC_PREAMBLE_EN_SHIFT)
+
+/* MII Data register */
+#define MII_DAT_REG			0x14
+#define MII_DAT_DATA_SHIFT		0
+#define MII_DAT_DATA_MASK		(0xffff << MII_DAT_DATA_SHIFT)
+#define MII_DAT_TA_SHIFT		16
+#define MII_DAT_TA_MASK			(0x3 << MII_DAT_TA_SHIFT)
+#define MII_DAT_REG_SHIFT		18
+#define MII_DAT_REG_MASK		(0x1f << MII_DAT_REG_SHIFT)
+#define MII_DAT_PHY_SHIFT		23
+#define MII_DAT_PHY_MASK		(0x1f << MII_DAT_PHY_SHIFT)
+#define MII_DAT_OP_SHIFT		28
+#define MII_DAT_OP_WRITE		(0x5 << MII_DAT_OP_SHIFT)
+#define MII_DAT_OP_READ			(0x6 << MII_DAT_OP_SHIFT)
+
+/* ETH Interrupts Mask register */
+#define ETH_IRMASK_REG			0x18
+
+/* ETH Interrupts register */
+#define ETH_IR_REG			0x1c
+#define ETH_IR_MII_SHIFT		0
+#define ETH_IR_MII_MASK			(1 << ETH_IR_MII_SHIFT)
+
+/* ETH Control register */
+#define ETH_CTL_REG			0x2c
+#define ETH_CTL_ENABLE_SHIFT		0
+#define ETH_CTL_ENABLE_MASK		(1 << ETH_CTL_ENABLE_SHIFT)
+#define ETH_CTL_DISABLE_SHIFT		1
+#define ETH_CTL_DISABLE_MASK		(1 << ETH_CTL_DISABLE_SHIFT)
+#define ETH_CTL_RESET_SHIFT		2
+#define ETH_CTL_RESET_MASK		(1 << ETH_CTL_RESET_SHIFT)
+#define ETH_CTL_EPHY_SHIFT		3
+#define ETH_CTL_EPHY_MASK		(1 << ETH_CTL_EPHY_SHIFT)
+
+/* ETH Transmit Control register */
+#define ETH_TXCTL_REG			0x30
+#define ETH_TXCTL_FD_SHIFT		0
+#define ETH_TXCTL_FD_MASK		(1 << ETH_TXCTL_FD_SHIFT)
+
+/* ETH Transmit Watermask register */
+#define ETH_TXWMARK_REG			0x34
+#define ETH_TXWMARK_WM_SHIFT		0
+#define ETH_TXWMARK_WM_MASK		(0x3f << ETH_TXWMARK_WM_SHIFT)
+
+/* MIB Control register */
+#define MIB_CTL_REG			0x38
+#define MIB_CTL_RDCLEAR_SHIFT		0
+#define MIB_CTL_RDCLEAR_MASK		(1 << MIB_CTL_RDCLEAR_SHIFT)
+
+/* ETH Perfect Match registers */
+#define ETH_PM_CNT			4
+#define ETH_PML_REG(x)			(0x58 + (x) * 0x8)
+#define ETH_PMH_REG(x)			(0x5c + (x) * 0x8)
+#define ETH_PMH_VALID_SHIFT		16
+#define ETH_PMH_VALID_MASK		(1 << ETH_PMH_VALID_SHIFT)
+
+/* MIB Counters registers */
+#define MIB_REG_CNT			55
+#define MIB_REG(x)			(0x200 + (x) * 4)
+
+/* ETH data */
+struct bcm6348_eth_priv {
+	void __iomem *base;
+	/* DMA */
+	struct dma rx_dma;
+	struct dma tx_dma;
+	/* PHY */
+	int phy_id;
+	struct phy_device *phy_dev;
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void bcm6348_eth_mac_disable(struct bcm6348_eth_priv *priv)
+{
+	/* disable emac */
+	clrsetbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK,
+			ETH_CTL_DISABLE_MASK);
+
+	/* wait until emac is disabled */
+	if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
+			      ETH_CTL_DISABLE_MASK, false,
+			      ETH_TIMEOUT, false))
+		pr_err("error disabling emac\n");
+}
+
+static void bcm6348_eth_mac_enable(struct bcm6348_eth_priv *priv)
+{
+	setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK);
+}
+
+static void bcm6348_eth_mac_reset(struct bcm6348_eth_priv *priv)
+{
+	/* reset emac */
+	writel_be(ETH_CTL_RESET_MASK, priv->base + ETH_CTL_REG);
+	wmb();
+
+	/* wait until emac is reset */
+	if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
+			      ETH_CTL_RESET_MASK, false,
+			      ETH_TIMEOUT, false))
+		pr_err("error resetting emac\n");
+}
+
+static int bcm6348_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	return dma_receive(&priv->rx_dma, (void *)packetp);
+}
+
+static int bcm6348_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	length = max(length, ETH_ZLEN);
+
+	return dma_send(&priv->tx_dma, (void **)packet, length);
+}
+
+static int bcm6348_eth_adjust_link(struct udevice *dev,
+				   struct phy_device *phydev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* mac duplex parameters */
+	if (phydev->duplex)
+		setbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
+	else
+		clrbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
+
+	/* rx flow control (pause frame handling) */
+	if (phydev->pause)
+		setbits_be32(priv->base + ETH_RXCFG_REG,
+			     ETH_RXCFG_ENFLOW_MASK);
+	else
+		clrbits_be32(priv->base + ETH_RXCFG_REG,
+			     ETH_RXCFG_ENFLOW_MASK);
+
+	return 0;
+}
+
+static int bcm6348_eth_start(struct udevice *dev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	int ret, i;
+
+	/* enable dma rx channel */
+	dma_enable(&priv->rx_dma);
+
+	/* enable dma tx channel */
+	dma_enable(&priv->tx_dma);
+
+	ret = phy_startup(priv->phy_dev);
+	if (ret) {
+		pr_err("could not initialize phy\n");
+		return ret;
+	}
+
+	if (!priv->phy_dev->link) {
+		pr_err("no phy link\n");
+		return -EIO;
+	}
+
+	bcm6348_eth_adjust_link(dev, priv->phy_dev);
+
+	/* zero mib counters */
+	for (i = 0; i < MIB_REG_CNT; i++)
+		writel_be(0, MIB_REG(i));
+
+	/* enable rx flow control */
+	setbits_be32(priv->base + ETH_RXCFG_REG, ETH_RXCFG_ENFLOW_MASK);
+
+	/* set max rx/tx length */
+	writel_be((ETH_MAX_MTU_SIZE << ETH_RXMAXLEN_SHIFT) &
+		  ETH_RXMAXLEN_MASK, priv->base + ETH_RXMAXLEN_REG);
+	writel_be((ETH_MAX_MTU_SIZE << ETH_TXMAXLEN_SHIFT) &
+		   ETH_TXMAXLEN_MASK, priv->base + ETH_TXMAXLEN_REG);
+
+	/* set correct transmit fifo watermark */
+	writel_be((ETH_TX_WATERMARK << ETH_TXWMARK_WM_SHIFT) &
+		  ETH_TXWMARK_WM_MASK, priv->base + ETH_TXWMARK_REG);
+
+	/* enable emac */
+	bcm6348_eth_mac_enable(priv);
+
+	/* clear interrupts */
+	writel_be(0, priv->base + ETH_IRMASK_REG);
+
+	return 0;
+}
+
+static void bcm6348_eth_stop(struct udevice *dev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* disable dma rx channel */
+	dma_disable(&priv->rx_dma);
+
+	/* disable dma tx channel */
+	dma_disable(&priv->tx_dma);
+
+	/* disable emac */
+	bcm6348_eth_mac_disable(priv);
+}
+
+static int bcm6348_eth_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	bool running = false;
+
+	/* check if emac is running */
+	if (readl_be(priv->base + ETH_CTL_REG) & ETH_CTL_ENABLE_MASK)
+		running = true;
+
+	/* disable emac */
+	if (running)
+		bcm6348_eth_mac_disable(priv);
+
+	/* set mac address */
+	writel_be((pdata->enetaddr[2] << 24) | (pdata->enetaddr[3]) << 16 |
+		  (pdata->enetaddr[4]) << 8 | (pdata->enetaddr[5]),
+		  priv->base + ETH_PML_REG(0));
+	writel_be((pdata->enetaddr[1]) | (pdata->enetaddr[0] << 8) |
+		  ETH_PMH_VALID_MASK, priv->base + ETH_PMH_REG(0));
+
+	/* enable emac */
+	if (running)
+		bcm6348_eth_mac_enable(priv);
+
+	return 0;
+}
+
+static const struct eth_ops bcm6348_eth_ops = {
+	.recv = bcm6348_eth_recv,
+	.send = bcm6348_eth_send,
+	.start = bcm6348_eth_start,
+	.stop = bcm6348_eth_stop,
+	.write_hwaddr = bcm6348_eth_write_hwaddr,
+};
+
+static const struct udevice_id bcm6348_eth_ids[] = {
+	{ .compatible = "brcm,bcm6348-enet", },
+	{ /* sentinel */ }
+};
+
+static int bcm6348_mdio_op(void __iomem *base, uint32_t data)
+{
+	/* make sure mii interrupt status is cleared */
+	writel_be(ETH_IR_MII_MASK, base + ETH_IR_REG);
+
+	/* issue mii op */
+	writel_be(data, base + MII_DAT_REG);
+
+	/* wait until emac is disabled */
+	return wait_for_bit_be32(base + ETH_IR_REG,
+				 ETH_IR_MII_MASK, true,
+				 ETH_TIMEOUT, false);
+}
+
+static int bcm6348_mdio_read(struct mii_dev *bus, int addr, int devaddr,
+			     int reg)
+{
+	void __iomem *base = bus->priv;
+	uint32_t val;
+
+	val = MII_DAT_OP_READ;
+	val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
+	val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
+	val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
+
+	if (bcm6348_mdio_op(base, val)) {
+		pr_err("%s: timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	val = readl_be(base + MII_DAT_REG) & MII_DAT_DATA_MASK;
+	val >>= MII_DAT_DATA_SHIFT;
+
+	return val;
+}
+
+static int bcm6348_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
+			      int reg, u16 value)
+{
+	void __iomem *base = bus->priv;
+	uint32_t val;
+
+	val = MII_DAT_OP_WRITE;
+	val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
+	val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
+	val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
+	val |= (value << MII_DAT_DATA_SHIFT) & MII_DAT_DATA_MASK;
+
+	if (bcm6348_mdio_op(base, val)) {
+		pr_err("%s: timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int bcm6348_mdio_init(const char *name, void __iomem *base)
+{
+	struct mii_dev *bus;
+
+	bus = mdio_alloc();
+	if (!bus) {
+		pr_err("%s: failed to allocate MDIO bus\n", __func__);
+		return -ENOMEM;
+	}
+
+	bus->read = bcm6348_mdio_read;
+	bus->write = bcm6348_mdio_write;
+	bus->priv = base;
+	snprintf(bus->name, sizeof(bus->name), "%s", name);
+
+	return mdio_register(bus);
+}
+
+static int bcm6348_phy_init(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	struct mii_dev *bus;
+
+	/* get mii bus */
+	bus = miiphy_get_dev_by_name(dev->name);
+
+	/* phy connect */
+	priv->phy_dev = phy_connect(bus, priv->phy_id, dev,
+				    pdata->phy_interface);
+	if (!priv->phy_dev) {
+		pr_err("%s: no phy device\n", __func__);
+		return -ENODEV;
+	}
+
+	priv->phy_dev->supported = (SUPPORTED_10baseT_Half |
+				    SUPPORTED_10baseT_Full |
+				    SUPPORTED_100baseT_Half |
+				    SUPPORTED_100baseT_Full |
+				    SUPPORTED_Autoneg |
+				    SUPPORTED_Pause |
+				    SUPPORTED_MII);
+	priv->phy_dev->advertising = priv->phy_dev->supported;
+
+	/* phy config */
+	phy_config(priv->phy_dev);
+
+	return 0;
+}
+
+static int bcm6348_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	void *blob = (void *)gd->fdt_blob;
+	int node = dev_of_offset(dev);
+	const char *phy_mode;
+	fdt_addr_t addr;
+	int phy_node, ret, i;
+
+	/* get base address */
+	addr = devfdt_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	/* get phy mode */
+	pdata->phy_interface = PHY_INTERFACE_MODE_NONE;
+	phy_mode = fdt_getprop(blob, node, "phy-mode", NULL);
+	if (phy_mode)
+		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_NONE)
+		return -ENODEV;
+
+	/* get phy */
+	phy_node = fdtdec_lookup_phandle(blob, node, "phy");
+	if (phy_node >= 0)
+		priv->phy_id = fdtdec_get_int(blob, phy_node, "reg", -1);
+	else
+		return -EINVAL;
+
+	/* get dma channels */
+	ret = dma_get_by_name(dev, "tx", &priv->tx_dma);
+	if (ret)
+		return -EINVAL;
+
+	ret = dma_get_by_name(dev, "rx", &priv->rx_dma);
+	if (ret)
+		return -EINVAL;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+		if (clk_enable(&clk))
+			pr_err("failed to enable clock %d\n", i);
+		clk_free(&clk);
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+		if (reset_deassert(&reset))
+			pr_err("failed to deassert reset %d\n", i);
+		reset_free(&reset);
+	}
+
+	/* get base addr */
+	priv->base = ioremap(addr, 0);
+	pdata->iobase = (phys_addr_t) priv->base;
+
+	/* disable emac */
+	bcm6348_eth_mac_disable(priv);
+
+	/* reset emac */
+	bcm6348_eth_mac_reset(priv);
+
+	/* select correct mii interface */
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_INTERNAL)
+		clrbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
+	else
+		setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
+
+	/* turn on mdc clock */
+	writel_be((0x1f << MII_SC_MDCFREQDIV_SHIFT) |
+		  MII_SC_PREAMBLE_EN_MASK, priv->base + MII_SC_REG);
+
+	/* set mib counters to not clear when read */
+	clrbits_be32(priv->base + MIB_CTL_REG, MIB_CTL_RDCLEAR_MASK);
+
+	/* initialize perfect match registers */
+	for (i = 0; i < ETH_PM_CNT; i++) {
+		writel_be(0, priv->base + ETH_PML_REG(i));
+		writel_be(0, priv->base + ETH_PMH_REG(i));
+	}
+
+	/* init mii bus */
+	ret = bcm6348_mdio_init(dev->name, priv->base);
+	if (ret)
+		return ret;
+
+	/* init phy */
+	ret = bcm6348_phy_init(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_eth) = {
+	.name = "bcm6348_eth",
+	.id = UCLASS_ETH,
+	.of_match = bcm6348_eth_ids,
+	.ops = &bcm6348_eth_ops,
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.priv_auto_alloc_size = sizeof(struct bcm6348_eth_priv),
+	.probe = bcm6348_eth_probe,
+};
diff --git a/include/configs/bmips_common.h b/include/configs/bmips_common.h
index 38bf7a272b..eb66512f67 100644
--- a/include/configs/bmips_common.h
+++ b/include/configs/bmips_common.h
@@ -7,6 +7,9 @@
 #ifndef __CONFIG_BMIPS_COMMON_H
 #define __CONFIG_BMIPS_COMMON_H
 
+/* ETH */
+#define CONFIG_PHY_RESET_DELAY		20
+
 /* UART */
 #define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200, \
 					  230400, 500000, 1500000 }
@@ -17,7 +20,7 @@
 
 /* Memory usage */
 #define CONFIG_SYS_MAXARGS		24
-#define CONFIG_SYS_MALLOC_LEN		(1024 * 1024)
+#define CONFIG_SYS_MALLOC_LEN		(2 * 1024 * 1024)
 #define CONFIG_SYS_BOOTPARAMS_LEN	(128 * 1024)
 #define CONFIG_SYS_CBSIZE		512
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 09/15] bmips: bcm6338: add support for bcm6348-enet
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                     ` (7 preceding siblings ...)
  2018-02-20 17:46   ` [U-Boot] [RFC v2 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 10/15] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: no changes

 arch/mips/dts/brcm,bcm6338.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6338.dtsi b/arch/mips/dts/brcm,bcm6338.dtsi
index 4125f71d9f..621278c9d1 100644
--- a/arch/mips/dts/brcm,bcm6338.dtsi
+++ b/arch/mips/dts/brcm,bcm6338.dtsi
@@ -145,5 +145,20 @@
 			dma-channels = <6>;
 			resets = <&periph_rst BCM6338_RST_DMAMEM>;
 		};
+
+		enet: ethernet at fffe2800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe2800 0x2dc>;
+			clocks = <&periph_clk BCM6338_CLK_ENET>;
+			resets = <&periph_rst BCM6338_RST_ENET>;
+			dmas = <&iudma BCM6338_DMA_ENET_RX>,
+			       <&iudma BCM6338_DMA_ENET_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
 	};
 };
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 10/15] bmips: enable f@st1704 enet support
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                     ` (8 preceding siblings ...)
  2018-02-20 17:46   ` [U-Boot] [RFC v2 09/15] bmips: bcm6338: " Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 11/15] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: no changes

 arch/mips/dts/sagem,f at st1704.dts     | 12 ++++++++++++
 configs/sagem_f at st1704_ram_defconfig |  9 ++++++++-
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/sagem,f at st1704.dts b/arch/mips/dts/sagem,f at st1704.dts
index dd0e5b8b7c..99d031f10a 100644
--- a/arch/mips/dts/sagem,f at st1704.dts
+++ b/arch/mips/dts/sagem,f at st1704.dts
@@ -40,6 +40,18 @@
 	};
 };
 
+&enet {
+	status = "okay";
+	phy = <&enetphy>;
+	phy-mode = "mii";
+
+	enetphy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio {
 	status = "okay";
 };
diff --git a/configs/sagem_f at st1704_ram_defconfig b/configs/sagem_f at st1704_ram_defconfig
index 0adcd46d51..1a640781b7 100644
--- a/configs/sagem_f at st1704_ram_defconfig
+++ b/configs/sagem_f at st1704_ram_defconfig
@@ -28,11 +28,15 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_SF=y
 CONFIG_CMD_SPI=y
-# CONFIG_CMD_NET is not set
+CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -41,6 +45,9 @@ CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_DM_RESET=y
 CONFIG_RESET_BCM6345=y
 # CONFIG_SPL_SERIAL_PRESENT is not set
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 11/15] bmips: bcm6348: add support for bcm6348-enet
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                     ` (9 preceding siblings ...)
  2018-02-20 17:46   ` [U-Boot] [RFC v2 10/15] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 12/15] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: no changes

 arch/mips/dts/brcm,bcm6348.dtsi | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6348.dtsi b/arch/mips/dts/brcm,bcm6348.dtsi
index d774c59665..e540865019 100644
--- a/arch/mips/dts/brcm,bcm6348.dtsi
+++ b/arch/mips/dts/brcm,bcm6348.dtsi
@@ -162,6 +162,32 @@
 			u-boot,dm-pre-reloc;
 		};
 
+		enet0: ethernet at fffe6000 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe6000 0x2dc>;
+			dmas = <&iudma BCM6348_DMA_ENET0_RX>,
+			       <&iudma BCM6348_DMA_ENET0_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		enet1: ethernet at fffe6800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe6800 0x2dc>;
+			dmas = <&iudma BCM6348_DMA_ENET1_RX>,
+			       <&iudma BCM6348_DMA_ENET1_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
 		iudma: dma-controller at fffe7000 {
 			compatible = "brcm,bcm6348-iudma";
 			reg = <0xfffe7000 0x1c>,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 12/15] bmips: enable ct-5361 enet support
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                     ` (10 preceding siblings ...)
  2018-02-20 17:46   ` [U-Boot] [RFC v2 11/15] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 13/15] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: no changes

 arch/mips/dts/comtrend,ct-5361.dts    | 12 ++++++++++++
 configs/comtrend_ct5361_ram_defconfig |  8 +++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/comtrend,ct-5361.dts b/arch/mips/dts/comtrend,ct-5361.dts
index 74dc09046c..a78aa877fc 100644
--- a/arch/mips/dts/comtrend,ct-5361.dts
+++ b/arch/mips/dts/comtrend,ct-5361.dts
@@ -35,6 +35,18 @@
 	};
 };
 
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/comtrend_ct5361_ram_defconfig b/configs/comtrend_ct5361_ram_defconfig
index 8b842606f5..0737772dd2 100644
--- a/configs/comtrend_ct5361_ram_defconfig
+++ b/configs/comtrend_ct5361_ram_defconfig
@@ -26,11 +26,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -38,6 +41,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6348_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 13/15] bmips: bcm6358: add support for bcm6348-enet
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                     ` (11 preceding siblings ...)
  2018-02-20 17:46   ` [U-Boot] [RFC v2 12/15] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 14/15] bmips: enable hg556a enet support Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 15/15] bmips: enable nb4-ser " Álvaro Fernández Rojas
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: no changes

 arch/mips/dts/brcm,bcm6358.dtsi | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6358.dtsi b/arch/mips/dts/brcm,bcm6358.dtsi
index 1468e4f63a..04329864c2 100644
--- a/arch/mips/dts/brcm,bcm6358.dtsi
+++ b/arch/mips/dts/brcm,bcm6358.dtsi
@@ -193,6 +193,34 @@
 			status = "disabled";
 		};
 
+		enet0: ethernet at fffe4000 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe4000 0x2dc>;
+			clocks = <&periph_clk BCM6358_CLK_ENET0>;
+			dmas = <&iudma BCM6358_DMA_ENET0_RX>,
+			       <&iudma BCM6358_DMA_ENET0_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		enet1: ethernet at fffe4800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe4800 0x2dc>;
+			clocks = <&periph_clk BCM6358_CLK_ENET1>;
+			dmas = <&iudma BCM6358_DMA_ENET1_RX>,
+			       <&iudma BCM6358_DMA_ENET1_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
 		iudma: dma-controller at fffe5000 {
 			compatible = "brcm,bcm6348-iudma";
 			reg = <0xfffe5000 0x24>,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 14/15] bmips: enable hg556a enet support
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                     ` (12 preceding siblings ...)
  2018-02-20 17:46   ` [U-Boot] [RFC v2 13/15] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  2018-02-20 17:46   ` [U-Boot] [RFC v2 15/15] bmips: enable nb4-ser " Álvaro Fernández Rojas
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: no changes

 arch/mips/dts/huawei,hg556a.dts     | 12 ++++++++++++
 configs/huawei_hg556a_ram_defconfig |  8 +++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/huawei,hg556a.dts b/arch/mips/dts/huawei,hg556a.dts
index a1e9c15ab9..2f99e0905c 100644
--- a/arch/mips/dts/huawei,hg556a.dts
+++ b/arch/mips/dts/huawei,hg556a.dts
@@ -94,6 +94,18 @@
 	status = "okay";
 };
 
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/huawei_hg556a_ram_defconfig b/configs/huawei_hg556a_ram_defconfig
index 7f7f34ed61..c7c7c6554f 100644
--- a/configs/huawei_hg556a_ram_defconfig
+++ b/configs/huawei_hg556a_ram_defconfig
@@ -26,11 +26,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -38,6 +41,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6358_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 15/15] bmips: enable nb4-ser enet support
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
                     ` (13 preceding siblings ...)
  2018-02-20 17:46   ` [U-Boot] [RFC v2 14/15] bmips: enable hg556a enet support Álvaro Fernández Rojas
@ 2018-02-20 17:46   ` Álvaro Fernández Rojas
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 17:46 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v2: no changes

 arch/mips/dts/sfr,nb4-ser.dts     | 24 ++++++++++++++++++++++++
 configs/sfr_nb4-ser_ram_defconfig |  8 +++++++-
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/sfr,nb4-ser.dts b/arch/mips/dts/sfr,nb4-ser.dts
index 473372faa1..73db45f9ea 100644
--- a/arch/mips/dts/sfr,nb4-ser.dts
+++ b/arch/mips/dts/sfr,nb4-ser.dts
@@ -54,6 +54,30 @@
 	status = "okay";
 };
 
+&enet0 {
+	status = "okay";
+	phy = <&enet0phy>;
+	phy-mode = "internal";
+
+	enet0phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/sfr_nb4-ser_ram_defconfig b/configs/sfr_nb4-ser_ram_defconfig
index fc323d879d..07b49a1a77 100644
--- a/configs/sfr_nb4-ser_ram_defconfig
+++ b/configs/sfr_nb4-ser_ram_defconfig
@@ -27,11 +27,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -40,6 +43,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6358_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 02/15] dma: add channels support
  2018-02-20 17:46   ` [U-Boot] [RFC v2 02/15] dma: add channels support Álvaro Fernández Rojas
@ 2018-02-20 18:49     ` Simon Glass
  2018-02-20 19:00       ` Álvaro Fernández Rojas
  2018-02-21 15:51       ` Álvaro Fernández Rojas
  0 siblings, 2 replies; 106+ messages in thread
From: Simon Glass @ 2018-02-20 18:49 UTC (permalink / raw)
  To: u-boot

Hi Alvaro,

On 20 February 2018 at 10:46, Álvaro Fernández Rojas <noltari@gmail.com> 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 <noltari@gmail.com>
> ---
>  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 <dm/device-internal.h>
>  #include <dma.h>
>  #include <dma-uclass.h>
> +#include <dt-structs.h>
>  #include <errno.h>
>
>  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.

> +       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 <dma.h>
> +#include <fdtdec.h>
>
>  /*
>   * 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

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 01/15] dma: move dma_ops to dma-uclass.h
  2018-02-20 17:46   ` [U-Boot] [RFC v2 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
@ 2018-02-20 18:49     ` Simon Glass
  2018-02-20 18:55       ` Álvaro Fernández Rojas
  0 siblings, 1 reply; 106+ messages in thread
From: Simon Glass @ 2018-02-20 18:49 UTC (permalink / raw)
  To: u-boot

Hi Alvaro,

On 20 February 2018 at 10:46, Álvaro Fernández Rojas <noltari@gmail.com> wrote:
> Move dma_ops to a separate header file, following other uclass implementations.
>
> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
> ---
>  drivers/dma/dma-uclass.c |  3 ++-
>  include/dma-uclass.h     | 38 ++++++++++++++++++++++++++++++++++++++
>  include/dma.h            | 22 ----------------------
>  3 files changed, 40 insertions(+), 23 deletions(-)
>  create mode 100644 include/dma-uclass.h
>
> diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
> index 3d0ce22fbc..6fd4e1b35d 100644
> --- a/drivers/dma/dma-uclass.c
> +++ b/drivers/dma/dma-uclass.c
> @@ -10,10 +10,11 @@
>   */
>
>  #include <common.h>
> -#include <dma.h>
>  #include <dm.h>
>  #include <dm/uclass-internal.h>
>  #include <dm/device-internal.h>
> +#include <dma.h>
> +#include <dma-uclass.h>
>  #include <errno.h>
>
>  DECLARE_GLOBAL_DATA_PTR;
> diff --git a/include/dma-uclass.h b/include/dma-uclass.h
> new file mode 100644
> index 0000000000..e29ad103f2
> --- /dev/null
> +++ b/include/dma-uclass.h
> @@ -0,0 +1,38 @@
> +/*
> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
> + * Copyright (C) 2015 Texas Instruments Incorporated, <www.ti.com>
> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#ifndef _DMA_UCLASS_H
> +#define _DMA_UCLASS_H
> +
> +/* See dma.h for background documentation. */
> +
> +#include <dma.h>
> +
> +/*
> + * 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

Is this the correct purpose for the transfer() method?
> +        *
> +        * @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.

Is this the number of bytes

What does this function actually do? Does it queue a transfer which
completes later? How do I check if it is done?

Please add a lot more docs here.

> +        * @return: 0 if OK, -ve on error
> +        */
> +       int (*transfer)(struct udevice *dev, int direction, void *dst,
> +                       void *src, size_t len);
> +};
> +
> +#endif /* _DMA_UCLASS_H */
> diff --git a/include/dma.h b/include/dma.h
> index 71fa77f2ea..89320f10d9 100644
> --- a/include/dma.h
> +++ b/include/dma.h
> @@ -28,28 +28,6 @@ enum dma_direction {
>  #define DMA_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, should be
> --
> 2.11.0
>

Regards,
Simon

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 01/15] dma: move dma_ops to dma-uclass.h
  2018-02-20 18:49     ` Simon Glass
@ 2018-02-20 18:55       ` Álvaro Fernández Rojas
  0 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 18:55 UTC (permalink / raw)
  To: u-boot

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 <noltari@gmail.com> wrote:
>> Move dma_ops to a separate header file, following other uclass implementations.
>>
>> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
>> ---
>>   drivers/dma/dma-uclass.c |  3 ++-
>>   include/dma-uclass.h     | 38 ++++++++++++++++++++++++++++++++++++++
>>   include/dma.h            | 22 ----------------------
>>   3 files changed, 40 insertions(+), 23 deletions(-)
>>   create mode 100644 include/dma-uclass.h
>>
>> diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
>> index 3d0ce22fbc..6fd4e1b35d 100644
>> --- a/drivers/dma/dma-uclass.c
>> +++ b/drivers/dma/dma-uclass.c
>> @@ -10,10 +10,11 @@
>>    */
>>
>>   #include <common.h>
>> -#include <dma.h>
>>   #include <dm.h>
>>   #include <dm/uclass-internal.h>
>>   #include <dm/device-internal.h>
>> +#include <dma.h>
>> +#include <dma-uclass.h>
>>   #include <errno.h>
>>
>>   DECLARE_GLOBAL_DATA_PTR;
>> diff --git a/include/dma-uclass.h b/include/dma-uclass.h
>> new file mode 100644
>> index 0000000000..e29ad103f2
>> --- /dev/null
>> +++ b/include/dma-uclass.h
>> @@ -0,0 +1,38 @@
>> +/*
>> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
>> + * Copyright (C) 2015 Texas Instruments Incorporated, <www.ti.com>
>> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
>> + *
>> + * SPDX-License-Identifier:    GPL-2.0+
>> + */
>> +
>> +#ifndef _DMA_UCLASS_H
>> +#define _DMA_UCLASS_H
>> +
>> +/* See dma.h for background documentation. */
>> +
>> +#include <dma.h>
>> +
>> +/*
>> + * 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
> Is this the correct purpose for the transfer() method?
This is just a copy&paste, that's what you can find in upstream dma.h ;D
Anyway, I will fix that.
>> +        *
>> +        * @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.
> Is this the number of bytes
>
> What does this function actually do? Does it queue a transfer which
> completes later? How do I check if it is done?
>
> Please add a lot more docs here.
Same as above.
>
>> +        * @return: 0 if OK, -ve on error
>> +        */
>> +       int (*transfer)(struct udevice *dev, int direction, void *dst,
>> +                       void *src, size_t len);
>> +};
>> +
>> +#endif /* _DMA_UCLASS_H */
>> diff --git a/include/dma.h b/include/dma.h
>> index 71fa77f2ea..89320f10d9 100644
>> --- a/include/dma.h
>> +++ b/include/dma.h
>> @@ -28,28 +28,6 @@ enum dma_direction {
>>   #define DMA_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, should be
>> --
>> 2.11.0
>>
> Regards,
> Simon
Regards,
Álvaro.

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 02/15] dma: add channels support
  2018-02-20 18:49     ` Simon Glass
@ 2018-02-20 19:00       ` Álvaro Fernández Rojas
  2018-02-21 15:51       ` Álvaro Fernández Rojas
  1 sibling, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-20 19:00 UTC (permalink / raw)
  To: u-boot

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 <noltari@gmail.com> 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 <noltari@gmail.com>
>> ---
>>   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 <dm/device-internal.h>
>>   #include <dma.h>
>>   #include <dma-uclass.h>
>> +#include <dt-structs.h>
>>   #include <errno.h>
>>
>>   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.
Ok, I did this some time ago and I used an older version of clk-uclass 
as a starting point.
I will switch to livetree in the next patch version.
>
>> +       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...
Ok.
>
>> +       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 <dma.h>
>> +#include <fdtdec.h>
>>
>>   /*
>>    * 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
Ok.
>
> Regards,
> Simon
Regards,
Álvaro.

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v2 02/15] dma: add channels support
  2018-02-20 18:49     ` Simon Glass
  2018-02-20 19:00       ` Álvaro Fernández Rojas
@ 2018-02-21 15:51       ` Álvaro Fernández Rojas
  1 sibling, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 15:51 UTC (permalink / raw)
  To: u-boot

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 <noltari@gmail.com> 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 <noltari@gmail.com>
>> ---
>>   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 <dm/device-internal.h>
>>   #include <dma.h>
>>   #include <dma-uclass.h>
>> +#include <dt-structs.h>
>>   #include <errno.h>
>>
>>   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 <dma.h>
>> +#include <fdtdec.h>
>>
>>   /*
>>    * 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.

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (15 preceding siblings ...)
  2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
@ 2018-02-21 16:10 ` Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
                     ` (14 more replies)
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
  18 siblings, 15 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

In order to add bcm6348-enet support, dma-uclass must be extended to support
dma channels and reworked to operate like the other dm uclass (clk, reset...).

This is a RFC, so please give you feedback on the things that I should
fix or rework.

v3: Introduce changes reported by Simon Glass:
 - Improve dma-uclass.h documentation.
 - Switch to live tree API.
v2: Introduce changes reported by Vignesh:
 - Respect current dma implementation.
 - Let dma_memcpy find a compatible dma device.
Other changes:
 - Fix bcm6348-iudma rx burst config.

Álvaro Fernández Rojas (15):
  dma: move dma_ops to dma-uclass.h
  dma: add channels support
  dma: add bcm6348-iudma support
  bmips: bcm6338: add bcm6348-iudma support
  bmips: bcm6348: add bcm6348-iudma support
  bmips: bcm6358: add bcm6348-iudma support
  phy: add support for internal phys
  net: add support for bcm6348-enet
  bmips: bcm6338: add support for bcm6348-enet
  bmips: enable f at st1704 enet support
  bmips: bcm6348: add support for bcm6348-enet
  bmips: enable ct-5361 enet support
  bmips: bcm6358: add support for bcm6348-enet
  bmips: enable hg556a enet support
  bmips: enable nb4-ser enet support

 arch/mips/dts/brcm,bcm6338.dtsi       |  29 ++
 arch/mips/dts/brcm,bcm6348.dtsi       |  42 +++
 arch/mips/dts/brcm,bcm6358.dtsi       |  46 +++
 arch/mips/dts/comtrend,ct-5361.dts    |  12 +
 arch/mips/dts/huawei,hg556a.dts       |  12 +
 arch/mips/dts/sagem,f at st1704.dts      |  12 +
 arch/mips/dts/sfr,nb4-ser.dts         |  24 ++
 configs/comtrend_ct5361_ram_defconfig |   8 +-
 configs/huawei_hg556a_ram_defconfig   |   8 +-
 configs/sagem_f at st1704_ram_defconfig  |   9 +-
 configs/sfr_nb4-ser_ram_defconfig     |   8 +-
 drivers/dma/Kconfig                   |  16 ++
 drivers/dma/Makefile                  |   1 +
 drivers/dma/bcm6348-iudma.c           | 505 +++++++++++++++++++++++++++++++++
 drivers/dma/dma-uclass.c              | 191 ++++++++++++-
 drivers/net/Kconfig                   |  10 +
 drivers/net/Makefile                  |   1 +
 drivers/net/bcm6348-eth.c             | 517 ++++++++++++++++++++++++++++++++++
 include/configs/bmips_common.h        |   5 +-
 include/dma-uclass.h                  | 117 ++++++++
 include/dma.h                         | 196 +++++++++++--
 include/dt-bindings/dma/bcm6338-dma.h |  15 +
 include/dt-bindings/dma/bcm6348-dma.h |  17 ++
 include/dt-bindings/dma/bcm6358-dma.h |  17 ++
 include/phy.h                         |   2 +
 25 files changed, 1784 insertions(+), 36 deletions(-)
 create mode 100644 drivers/dma/bcm6348-iudma.c
 create mode 100644 drivers/net/bcm6348-eth.c
 create mode 100644 include/dma-uclass.h
 create mode 100644 include/dt-bindings/dma/bcm6338-dma.h
 create mode 100644 include/dt-bindings/dma/bcm6348-dma.h
 create mode 100644 include/dt-bindings/dma/bcm6358-dma.h

-- 
2.11.0

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 01/15] dma: move dma_ops to dma-uclass.h
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-22 16:18     ` Simon Glass
  2018-02-21 16:10   ` [U-Boot] [RFC v3 02/15] dma: add channels support Álvaro Fernández Rojas
                     ` (13 subsequent siblings)
  14 siblings, 1 reply; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Move dma_ops to a separate header file, following other uclass implementations.
While doing so, this patch also improves dma_ops documentation.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: Introduce changes reported by Simon Glass:
  - Improve dma-uclass.h documentation.
  - Switch to live tree API.

 drivers/dma/dma-uclass.c |  3 ++-
 include/dma-uclass.h     | 39 +++++++++++++++++++++++++++++++++++++++
 include/dma.h            | 22 ----------------------
 3 files changed, 41 insertions(+), 23 deletions(-)
 create mode 100644 include/dma-uclass.h

diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
index 3d0ce22fbc..6fd4e1b35d 100644
--- a/drivers/dma/dma-uclass.c
+++ b/drivers/dma/dma-uclass.c
@@ -10,10 +10,11 @@
  */
 
 #include <common.h>
-#include <dma.h>
 #include <dm.h>
 #include <dm/uclass-internal.h>
 #include <dm/device-internal.h>
+#include <dma.h>
+#include <dma-uclass.h>
 #include <errno.h>
 
 DECLARE_GLOBAL_DATA_PTR;
diff --git a/include/dma-uclass.h b/include/dma-uclass.h
new file mode 100644
index 0000000000..abf750a5ce
--- /dev/null
+++ b/include/dma-uclass.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DMA_UCLASS_H
+#define _DMA_UCLASS_H
+
+/* See dma.h for background documentation. */
+
+#include <dma.h>
+
+/*
+ * struct dma_ops - Driver model DMA operations
+ *
+ * The uclass interface is implemented by all DMA devices which use
+ * driver model.
+ */
+struct dma_ops {
+	/**
+	 * transfer() - Issue a DMA transfer. The implementation must
+	 *   wait until the transfer is done.
+	 *
+	 * @dev: The DMA device
+	 * @direction: direction of data transfer (should be one from
+	 *   enum dma_direction)
+	 * @dst: The destination pointer.
+	 * @src: The source pointer.
+	 * @len: Length of the data to be copied (number of bytes).
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*transfer)(struct udevice *dev, int direction, void *dst,
+			void *src, size_t len);
+};
+
+#endif /* _DMA_UCLASS_H */
diff --git a/include/dma.h b/include/dma.h
index 71fa77f2ea..89320f10d9 100644
--- a/include/dma.h
+++ b/include/dma.h
@@ -28,28 +28,6 @@ enum dma_direction {
 #define DMA_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, should be
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 02/15] dma: add channels support
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-22 16:18     ` Simon Glass
  2018-02-21 16:10   ` [U-Boot] [RFC v3 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
                     ` (12 subsequent siblings)
  14 siblings, 1 reply; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

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 <noltari@gmail.com>
---
 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 6fd4e1b35d..f4ba883b12 100644
--- a/drivers/dma/dma-uclass.c
+++ b/drivers/dma/dma-uclass.c
@@ -1,24 +1,200 @@
 /*
  * Direct Memory Access U-Class driver
  *
- * (C) Copyright 2015
- *     Texas Instruments Incorporated, <www.ti.com>
- *
- * Author: Mugunthan V N <mugunthanvnm@ti.com>
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
  *
  * SPDX-License-Identifier:     GPL-2.0+
  */
 
 #include <common.h>
 #include <dm.h>
-#include <dm/uclass-internal.h>
-#include <dm/device-internal.h>
+#include <dm/read.h>
 #include <dma.h>
 #include <dma-uclass.h>
+#include <dt-structs.h>
 #include <errno.h>
 
 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, &dma->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,
+					 &args);
+	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, &dev_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, &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);
+	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, 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 abf750a5ce..38f0fe94f8 100644
--- a/include/dma-uclass.h
+++ b/include/dma-uclass.h
@@ -13,6 +13,8 @@
 
 #include <dma.h>
 
+struct ofnode_phandle_args;
+
 /*
  * struct dma_ops - Driver model DMA operations
  *
@@ -20,6 +22,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 ofnode_phandle_args *args);
+	/**
+	 * request - Request a translated DMA.
+	 *
+	 * The DMA core calls this function as the second step in
+	 * implementing a client's dma_get_by_*() call, following a successful
+	 * xxx_xlate() call, or as the only step in implementing a client's
+	 * dma_request() call.
+	 *
+	 * @dma: The DMA struct to request; this has been filled in by
+	 *   a previoux xxx_xlate() function call, or by the caller of
+	 *   dma_request().
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*request)(struct dma *dma);
+	/**
+	 * free - Free a previously requested dma.
+	 *
+	 * This is the implementation of the client dma_free() API.
+	 *
+	 * @dma: The DMA to free.
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*free)(struct dma *dma);
+	/**
+	 * enable() - Enable a DMA Channel.
+	 *
+	 * @dma: The DMA Channel to manipulate.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*enable)(struct dma *dma);
+	/**
+	 * disable() - Disable a DMA Channel.
+	 *
+	 * @dma: The DMA Channel to manipulate.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*disable)(struct dma *dma);
+	/**
+	 * 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);
+#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, <www.ti.com>
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
  *
  * SPDX-License-Identifier:     GPL-2.0+
  */
@@ -8,6 +9,9 @@
 #ifndef _DMA_H_
 #define _DMA_H_
 
+#include <linux/errno.h>
+#include <linux/types.h>
+
 /*
  * 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 provider. A provider will
+ * often implement multiple separate DMAs, since the hardware it manages
+ * often has this capability. dma_uclass.h describes the interface which
+ * DMA providers must implement.
+ *
+ * DMA consumers/clients are the HW modules driven by the DMA channels. This
+ * header file describes the API used by drivers for those HW modules.
+ */
+
+struct udevice;
+
+/**
+ * struct dma - A handle to (allowing control of) a single DMA.
+ *
+ * Clients provide storage for DMA handles. The content of the structure is
+ * managed solely by the DMA API and DMA drivers. A DMA struct is
+ * initialized by "get"ing the DMA struct. The DMA struct is passed to all
+ * other DMA APIs to identify which DMA channel to operate upon.
+ *
+ * @dev: The device which implements the DMA channel.
+ * @id: The DMA channel ID within the provider.
+ *
+ * Currently, the DMA API assumes that a single integer ID is enough to
+ * identify and configure any DMA channel for any DMA provider. If this
+ * assumption becomes invalid in the future, the struct could be expanded to
+ * either (a) add more fields to allow DMA providers to store additional
+ * information, or (b) replace the id field with an opaque pointer, which the
+ * provider would dynamically allocated during its .of_xlate op, and process
+ * during is .request op. This may require the addition of an extra op to clean
+ * up the allocation.
+ */
+struct dma {
+	struct udevice *dev;
+	/*
+	 * Written by of_xlate. We assume a single id is enough for now. In the
+	 * future, we might add more fields here.
+	 */
+	unsigned long id;
+};
+
+# if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DMA)
+struct phandle_1_arg;
+int dma_get_by_index_platdata(struct udevice *dev, int index,
+			      struct phandle_1_arg *cells, struct dma *dma);
+
+/**
+ * dma_get_by_index - Get/request a DMA by integer index.
+ *
+ * This looks up and requests a DMA. The index is relative to the client
+ * device; each device is assumed to have n DMAs associated with it somehow,
+ * and this function finds and requests one of them. The mapping of client
+ * device DMA indices to provider DMAs may be via device-tree properties,
+ * board-provided mapping tables, or some other mechanism.
+ *
+ * @dev:	The client device.
+ * @index:	The index of the DMA to request, within the client's list of
+ *		DMA channels.
+ * @dma:	A pointer to a DMA struct to initialize.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_get_by_index(struct udevice *dev, int index, struct dma *dma);
+
+/**
+ * dma_get_by_name - Get/request a DMA by name.
+ *
+ * This looks up and requests a DMA. The name is relative to the client
+ * device; each device is assumed to have n DMAs associated with it somehow,
+ * and this function finds and requests one of them. The mapping of client
+ * device DMA names to provider DMAs may be via device-tree properties,
+ * board-provided mapping tables, or some other mechanism.
+ *
+ * @dev:	The client device.
+ * @name:	The name of the DMA to request, within the client's list of
+ *		DMA channels.
+ * @dma:	A pointer to a DMA struct to initialize.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma);
+# else
+static inline int dma_get_by_index(struct udevice *dev, int index,
+				   struct dma *dma)
+{
+	return -ENOSYS;
+}
+
+static inline int dma_get_by_name(struct udevice *dev, const char *name,
+			   struct dma *dma)
+{
+	return -ENOSYS;
+}
+# endif
+
+/**
+ * dma_request - Request a DMA by provider-specific ID.
+ *
+ * This requests a DMA using a provider-specific ID. Generally, this function
+ * should not be used, since dma_get_by_index/name() provide an interface that
+ * better separates clients from intimate knowledge of DMA providers.
+ * However, this function may be useful in core SoC-specific code.
+ *
+ * @dev: The DMA provider device.
+ * @dma: A pointer to a DMA struct to initialize. The caller must
+ *	 have already initialized any field in this struct which the
+ *	 DMA provider uses to identify the DMA channel.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_request(struct udevice *dev, struct dma *dma);
+
+/**
+ * dma_free - Free a previously requested DMA.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_free(struct dma *dma);
+
+/**
+ * dma_enable() - Enable (turn on) a DMA channel.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return zero on success, or -ve error code.
+ */
+int dma_enable(struct dma *dma);
+
+/**
+ * dma_disable() - Disable (turn off) a DMA channel.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return zero on success, or -ve error code.
+ */
+int dma_disable(struct dma *dma);
+
+/**
+ * dma_receive() - Receive a DMA transfer.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @dst: The destination pointer.
+ * @return zero on success, or -ve error code.
+ */
+int dma_receive(struct dma *dma, void **dst);
+
+/**
+ * dma_send() - Send a DMA transfer.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @src: The source pointer.
+ * @len: Length of the data to be sent (number of bytes).
+ * @return zero on success, or -ve error code.
+ */
+int dma_send(struct dma *dma, void *src, size_t len);
+#endif /* CONFIG_DMA_CHANNELS */
+
 /*
  * dma_get_device - get a DMA device which supports transfer
  * type of transfer_type
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 03/15] dma: add bcm6348-iudma support
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 02/15] dma: add channels support Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-22 19:50     ` Grygorii Strashko
  2018-02-21 16:10   ` [U-Boot] [RFC v3 04/15] bmips: bcm6338: " Álvaro Fernández Rojas
                     ` (11 subsequent siblings)
  14 siblings, 1 reply; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

BCM6348 IUDMA controller is present on multiple BMIPS (BCM63xx) SoCs.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: Fix dma rx burst config and select DMA_CHANNELS.

 drivers/dma/Kconfig         |   9 +
 drivers/dma/Makefile        |   1 +
 drivers/dma/bcm6348-iudma.c | 505 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 515 insertions(+)
 create mode 100644 drivers/dma/bcm6348-iudma.c

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 21b2c0dcaa..9afa158b51 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -19,6 +19,15 @@ config DMA_CHANNELS
 	  Enable channels support for DMA. Some DMA controllers have multiple
 	  channels which can either transfer data to/from different devices.
 
+config BCM6348_IUDMA
+	bool "BCM6348 IUDMA driver"
+	depends on ARCH_BMIPS
+	select DMA_CHANNELS
+	help
+	  Enable the BCM6348 IUDMA driver.
+	  This driver support data transfer from devices to
+	  memory and from memory to devices.
+
 config TI_EDMA3
 	bool "TI EDMA3 driver"
 	help
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 39b78b2a3d..b2b4147349 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_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_BCM6348_IUDMA) += bcm6348-iudma.o
 obj-$(CONFIG_FSL_DMA) += fsl_dma.o
 obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
 obj-$(CONFIG_TI_EDMA3) += ti-edma3.o
diff --git a/drivers/dma/bcm6348-iudma.c b/drivers/dma/bcm6348-iudma.c
new file mode 100644
index 0000000000..8016a58be2
--- /dev/null
+++ b/drivers/dma/bcm6348-iudma.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/dma/bcm63xx-iudma.c:
+ *	Copyright (C) 2015 Simon Arlott <simon@fire.lp0.eu>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
+ *	Copyright (C) 2000-2010 Broadcom Corporation
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/bcmdrivers/opensource/net/enet/impl4/bcmenet.c:
+ *	Copyright (C) 2010 Broadcom Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma-uclass.h>
+#include <memalign.h>
+#include <net.h>
+#include <reset.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ALIGN_END_ADDR(type, ptr, size)	\
+	((unsigned long)(ptr) + roundup((size) * sizeof(type), \
+	 ARCH_DMA_MINALIGN))
+
+/* DMA Channels */
+#define DMA_CHAN_FLOWC(x)		((x) >> 1)
+#define DMA_CHAN_FLOWC_MAX		8
+#define DMA_CHAN_MAX			16
+#define DMA_CHAN_SIZE			0x10
+#define DMA_CHAN_TOUT			500
+
+/* DMA Global Configuration register */
+#define DMA_CFG_REG			0x00
+#define DMA_CFG_ENABLE_SHIFT		0
+#define DMA_CFG_ENABLE_MASK		(1 << DMA_CFG_ENABLE_SHIFT)
+#define DMA_CFG_FLOWC_ENABLE(x)		BIT(DMA_CHAN_FLOWC(x) + 1)
+#define DMA_CFG_NCHANS_SHIFT		24
+#define DMA_CFG_NCHANS_MASK		(0xf << DMA_CFG_NCHANS_SHIFT)
+
+/* DMA Global Flow Control Threshold registers */
+#define DMA_FLOWC_THR_LO_REG(x)		(0x04 + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_THR_LO_SHIFT		0
+#define DMA_FLOWC_THR_LO_MASK		(5 << DMA_FLOWC_THR_LO_SHIFT)
+
+#define DMA_FLOWC_THR_HI_REG(x)		(0x08 + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_THR_HI_SHIFT		0
+#define DMA_FLOWC_THR_HI_MASK		(10 << DMA_FLOWC_THR_HI_SHIFT)
+
+/* DMA Global Flow Control Buffer Allocation registers */
+#define DMA_FLOWC_ALLOC_REG(x)		(0x0c + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_ALLOC_FORCE_SHIFT	31
+#define DMA_FLOWC_ALLOC_FORCE_MASK	(1 << DMA_FLOWC_ALLOC_FORCE_SHIFT)
+
+/* DMA Global Reset register */
+#define DMA_RST_REG			0x34
+#define DMA_RST_CHAN_SHIFT		0
+#define DMA_RST_CHAN_MASK(x)		(1 << x)
+
+/* DMA Channel Configuration register */
+#define DMAC_CFG_REG(x)			(DMA_CHAN_SIZE * (x) + 0x00)
+#define DMAC_CFG_ENABLE_SHIFT		0
+#define DMAC_CFG_ENABLE_MASK		(1 << DMAC_CFG_ENABLE_SHIFT)
+#define DMAC_CFG_PKT_HALT_SHIFT		1
+#define DMAC_CFG_PKT_HALT_MASK		(1 << DMAC_CFG_PKT_HALT_SHIFT)
+#define DMAC_CFG_BRST_HALT_SHIFT	2
+#define DMAC_CFG_BRST_HALT_MASK		(1 << DMAC_CFG_BRST_HALT_SHIFT)
+
+/* DMA Channel Interrupts registers */
+#define DMAC_IR_ST_REG(x)		(DMA_CHAN_SIZE * (x) + 0x04)
+#define DMAC_IR_EN_REG(x)		(DMA_CHAN_SIZE * (x) + 0x08)
+
+#define DMAC_IR_DONE_SHIFT		2
+#define DMAC_IR_DONE_MASK		(1 << DMAC_IR_DONE_SHIFT)
+
+/* DMA Channel Max Burst Length register */
+#define DMAC_BURST_REG(x)		(DMA_CHAN_SIZE * (x) + 0x0c)
+#define DMAC_BURST_MAX_SHIFT		0
+#define DMAC_BURST_MAX_MASK		(16 << DMAC_BURST_MAX_SHIFT)
+
+/* DMA SRAM Descriptor Ring Start register */
+#define DMAS_RSTART_REG(x)		(DMA_CHAN_SIZE * (x) + 0x00)
+
+/* DMA SRAM State/Bytes done/ring offset register */
+#define DMAS_STATE_DATA_REG(x)		(DMA_CHAN_SIZE * (x) + 0x04)
+
+/* DMA SRAM Buffer Descriptor status and length register */
+#define DMAS_DESC_LEN_STATUS_REG(x)	(DMA_CHAN_SIZE * (x) + 0x08)
+
+/* DMA SRAM Buffer Descriptor status and length register */
+#define DMAS_DESC_BASE_BUFPTR_REG(x)	(DMA_CHAN_SIZE * (x) + 0x0c)
+
+struct bcm6348_dma_desc {
+	uint16_t length;
+
+	uint16_t status;
+#define DMAD_ST_CRC_SHIFT	8
+#define DMAD_ST_CRC_MASK	(1 << DMAD_ST_CRC_SHIFT)
+#define DMAD_ST_WRAP_SHIFT	12
+#define DMAD_ST_WRAP_MASK	(1 << DMAD_ST_WRAP_SHIFT)
+#define DMAD_ST_SOP_SHIFT	13
+#define DMAD_ST_SOP_MASK	(1 << DMAD_ST_SOP_SHIFT)
+#define DMAD_ST_EOP_SHIFT	14
+#define DMAD_ST_EOP_MASK	(1 << DMAD_ST_EOP_SHIFT)
+#define DMAD_ST_OWN_SHIFT	15
+#define DMAD_ST_OWN_MASK	(1 << DMAD_ST_OWN_SHIFT)
+
+	uint32_t address;
+} __attribute__((aligned(1)));
+
+struct bcm6348_chan_priv {
+	void __iomem *dma_ring;
+	uint8_t dma_ring_size;
+	uint8_t desc_id;
+};
+
+struct bcm6348_iudma_priv {
+	void __iomem *base;
+	void __iomem *chan;
+	void __iomem *sram;
+	struct bcm6348_chan_priv **ch_priv;
+	uint8_t n_channels;
+};
+
+static bool bcm6348_iudma_chan_is_rx(uint8_t ch)
+{
+	return !(ch & 1);
+}
+
+static void bcm6348_iudma_chan_stop(struct bcm6348_iudma_priv *priv,
+				    uint8_t ch)
+{
+	unsigned int timeout = DMA_CHAN_TOUT;
+
+	/* disable dma channel interrupts */
+	writel_be(0, priv->chan + DMAC_IR_EN_REG(ch));
+
+	do {
+		uint32_t cfg, halt;
+
+		if (timeout > DMA_CHAN_TOUT / 2)
+			halt = DMAC_CFG_PKT_HALT_MASK;
+		else
+			halt = DMAC_CFG_BRST_HALT_MASK;
+
+		/* try to stop dma channel */
+		writel_be(halt, priv->chan + DMAC_CFG_REG(ch));
+		mb();
+
+		/* check if channel was stopped */
+		cfg = readl_be(priv->chan + DMAC_CFG_REG(ch));
+		if (!(cfg & DMAC_CFG_ENABLE_MASK))
+			break;
+
+		udelay(1);
+	} while (--timeout);
+
+	if (!timeout)
+		pr_err("unable to stop channel %u\n", ch);
+
+	/* reset dma channel */
+	setbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
+	clrbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
+}
+
+static int bcm6348_iudma_disable(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+
+	bcm6348_iudma_chan_stop(priv, dma->id);
+
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		writel_be(DMA_FLOWC_ALLOC_FORCE_MASK,
+			  DMA_FLOWC_ALLOC_REG(dma->id));
+
+	return 0;
+}
+
+static int bcm6348_iudma_enable(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	uint8_t i;
+
+	/* init dma rings */
+	dma_desc = ch_priv->dma_ring;
+	for (i = 0; i < ch_priv->dma_ring_size; i++) {
+		if (bcm6348_iudma_chan_is_rx(dma->id)) {
+			dma_desc->status = DMAD_ST_OWN_MASK;
+			dma_desc->length = PKTSIZE_ALIGN;
+			dma_desc->address = virt_to_phys(net_rx_packets[i]);
+		} else {
+			dma_desc->status = 0;
+			dma_desc->length = 0;
+			dma_desc->address = 0;
+		}
+
+		if (i == ch_priv->dma_ring_size - 1)
+			dma_desc->status |= DMAD_ST_WRAP_MASK;
+
+		if (bcm6348_iudma_chan_is_rx(dma->id))
+			writel_be(1,
+				  priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
+
+		dma_desc++;
+	}
+
+	/* init to first descriptor */
+	ch_priv->desc_id = 0;
+
+	/* force cache writeback */
+	flush_dcache_range((ulong)ch_priv->dma_ring,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, ch_priv->dma_ring,
+			       ch_priv->dma_ring_size));
+
+	/* clear sram */
+	writel_be(0, priv->sram + DMAS_STATE_DATA_REG(dma->id));
+	writel_be(0, priv->sram + DMAS_DESC_LEN_STATUS_REG(dma->id));
+	writel_be(0, priv->sram + DMAS_DESC_BASE_BUFPTR_REG(dma->id));
+
+	/* set dma ring start */
+	writel_be(virt_to_phys(ch_priv->dma_ring),
+		  priv->sram + DMAS_RSTART_REG(dma->id));
+
+	/* set flow control */
+	if (bcm6348_iudma_chan_is_rx(dma->id)) {
+		u32 val;
+
+		setbits_be32(priv->base + DMA_CFG_REG,
+			     DMA_CFG_FLOWC_ENABLE(dma->id));
+
+		val = ch_priv->dma_ring_size / 3;
+		writel_be(val, priv->base + DMA_FLOWC_THR_LO_REG(dma->id));
+
+		val = (ch_priv->dma_ring_size * 2) / 3;
+		writel_be(val, priv->base + DMA_FLOWC_THR_HI_REG(dma->id));
+	}
+
+	/* set dma max burst */
+	writel_be(ch_priv->dma_ring_size,
+		  priv->chan + DMAC_BURST_REG(dma->id));
+
+	/* clear interrupts */
+	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_ST_REG(dma->id));
+	writel_be(0, priv->chan + DMAC_IR_EN_REG(dma->id));
+
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	return 0;
+}
+
+static int bcm6348_iudma_request(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv;
+
+	/* check if channel is valid */
+	if (dma->id >= priv->n_channels)
+		return -ENODEV;
+
+	/* alloc channel private data */
+	priv->ch_priv[dma->id] = calloc(1, sizeof(struct bcm6348_chan_priv));
+	if (!priv->ch_priv[dma->id])
+		return -ENOMEM;
+	ch_priv = priv->ch_priv[dma->id];
+
+	/* alloc dma ring */
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		ch_priv->dma_ring_size = PKTBUFSRX;
+	else
+		ch_priv->dma_ring_size = 1;
+	ch_priv->dma_ring =
+		malloc_cache_aligned(sizeof(struct bcm6348_dma_desc) *
+				     ch_priv->dma_ring_size);
+	if (!ch_priv->dma_ring)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int bcm6348_iudma_receive(struct dma *dma, void **dst)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	void __iomem *dma_buff;
+	uint16_t status;
+	int ret;
+
+	/* get dma ring descriptor address */
+	dma_desc = ch_priv->dma_ring;
+	dma_desc += ch_priv->desc_id;
+
+	/* invalidate cache data */
+	invalidate_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* check dma own */
+	if (dma_desc->status & DMAD_ST_OWN_MASK)
+		return 0;
+
+	/* check dma end */
+	if (!(dma_desc->status & DMAD_ST_EOP_MASK))
+		return -EINVAL;
+
+	/* get dma buff descriptor address */
+	dma_buff = phys_to_virt(dma_desc->address);
+
+	/* invalidate cache data */
+	invalidate_dcache_range((ulong)dma_buff,
+				(ulong)(dma_buff + PKTSIZE_ALIGN));
+
+	/* get dma data */
+	*dst = dma_buff;
+	ret = dma_desc->length;
+
+	/* reinit dma descriptor */
+	status = dma_desc->status & DMAD_ST_WRAP_MASK;
+	status |= DMAD_ST_OWN_MASK;
+
+	dma_desc->length = PKTSIZE_ALIGN;
+	dma_desc->status = status;
+
+	/* flush cache */
+	flush_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* set flow control buffer alloc */
+	writel_be(1, priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
+
+	/* enable dma */
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	/* set interrupt */
+	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_EN_REG(dma->id));
+
+	/* increment dma descriptor */
+	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->dma_ring_size;
+
+	return ret - 4;
+}
+
+static int bcm6348_iudma_send(struct dma *dma, void *src, size_t len)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	uint16_t val;
+
+	/* get dma ring descriptor address */
+	dma_desc = ch_priv->dma_ring;
+	dma_desc += ch_priv->desc_id;
+
+	dma_desc->address = virt_to_phys(src);
+
+	/* config dma descriptor */
+	val = (DMAD_ST_OWN_MASK |
+	       DMAD_ST_EOP_MASK |
+	       DMAD_ST_CRC_MASK |
+	       DMAD_ST_SOP_MASK);
+	if (ch_priv->desc_id == ch_priv->dma_ring_size - 1)
+		val |= DMAD_ST_WRAP_MASK;
+
+	dma_desc->length = len;
+	dma_desc->status = val;
+
+	/* flush cache */
+	flush_dcache_range((ulong)src, (ulong)src + PKTSIZE_ALIGN);
+
+	/* flush cache */
+	flush_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* enable dma */
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	/* set interrupt */
+	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_EN_REG(dma->id));
+
+	/* poll dma status */
+	do {
+		/* invalidate cache */
+		invalidate_dcache_range((ulong)dma_desc,
+			ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+		if (!(dma_desc->status & DMAD_ST_OWN_MASK))
+			break;
+	} while(1);
+
+	/* increment dma descriptor */
+	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->dma_ring_size;
+
+	return 0;
+}
+
+static const struct dma_ops bcm6348_iudma_ops = {
+	.disable = bcm6348_iudma_disable,
+	.enable = bcm6348_iudma_enable,
+	.request = bcm6348_iudma_request,
+	.receive = bcm6348_iudma_receive,
+	.send = bcm6348_iudma_send,
+};
+
+static const struct udevice_id bcm6348_iudma_ids[] = {
+	{ .compatible = "brcm,bcm6348-iudma", },
+	{ /* sentinel */ }
+};
+
+static int bcm6348_iudma_probe(struct udevice *dev)
+{
+	struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+	uint8_t ch;
+	int i;
+
+	uc_priv->supported = DMA_SUPPORTS_DEV_TO_MEM |
+			     DMA_SUPPORTS_MEM_TO_DEV;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+		if (clk_enable(&clk))
+			pr_err("failed to enable clock %d\n", i);
+		clk_free(&clk);
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+		if (reset_deassert(&reset))
+			pr_err("failed to deassert reset %d\n", i);
+		reset_free(&reset);
+	}
+
+	/* dma global base address */
+	addr = devfdt_get_addr_name(dev, "dma");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->base = ioremap(addr, 0);
+
+	/* dma channels base address */
+	addr = devfdt_get_addr_name(dev, "dma-channels");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->chan = ioremap(addr, 0);
+
+	/* dma sram base address */
+	addr = devfdt_get_addr_name(dev, "dma-sram");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->sram = ioremap(addr, 0);
+
+	/* disable dma controller */
+	clrbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
+
+	/* get number of channels */
+	priv->n_channels = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+					   "dma-channels", 8);
+	if (priv->n_channels > DMA_CHAN_MAX)
+		return -EINVAL;
+
+	/* alloc channel private data pointers */
+	priv->ch_priv = calloc(priv->n_channels,
+			       sizeof(struct bcm6348_chan_priv*));
+	if (!priv->ch_priv)
+		return -ENOMEM;
+
+	/* stop dma channels */
+	for (ch = 0; ch < priv->n_channels; ch++)
+		bcm6348_iudma_chan_stop(priv, ch);
+
+	/* enable dma controller */
+	setbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_iudma) = {
+	.name = "bcm6348_iudma",
+	.id = UCLASS_DMA,
+	.of_match = bcm6348_iudma_ids,
+	.ops = &bcm6348_iudma_ops,
+	.priv_auto_alloc_size = sizeof(struct bcm6348_iudma_priv),
+	.probe = bcm6348_iudma_probe,
+};
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 04/15] bmips: bcm6338: add bcm6348-iudma support
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (2 preceding siblings ...)
  2018-02-21 16:10   ` [U-Boot] [RFC v3 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 05/15] bmips: bcm6348: " Álvaro Fernández Rojas
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6338.dtsi       | 14 ++++++++++++++
 include/dt-bindings/dma/bcm6338-dma.h | 15 +++++++++++++++
 2 files changed, 29 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6338-dma.h

diff --git a/arch/mips/dts/brcm,bcm6338.dtsi b/arch/mips/dts/brcm,bcm6338.dtsi
index 0cab44cb8d..4125f71d9f 100644
--- a/arch/mips/dts/brcm,bcm6338.dtsi
+++ b/arch/mips/dts/brcm,bcm6338.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6338-clock.h>
+#include <dt-bindings/dma/bcm6338-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6338-reset.h>
 #include "skeleton.dtsi"
@@ -131,5 +132,18 @@
 			reg = <0xfffe3100 0x38>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller at fffe2400 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe2400 0x1c>,
+			      <0xfffe2500 0x60>,
+			      <0xfffe2600 0x60>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <6>;
+			resets = <&periph_rst BCM6338_RST_DMAMEM>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6338-dma.h b/include/dt-bindings/dma/bcm6338-dma.h
new file mode 100644
index 0000000000..5dd66239b4
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6338-dma.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6338_H
+#define __DT_BINDINGS_DMA_BCM6338_H
+
+#define BCM6338_DMA_ENET_RX	0
+#define BCM6338_DMA_ENET_TX	1
+
+#endif /* __DT_BINDINGS_DMA_BCM6338_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 05/15] bmips: bcm6348: add bcm6348-iudma support
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (3 preceding siblings ...)
  2018-02-21 16:10   ` [U-Boot] [RFC v3 04/15] bmips: bcm6338: " Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 06/15] bmips: bcm6358: " Álvaro Fernández Rojas
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6348.dtsi       | 16 ++++++++++++++++
 include/dt-bindings/dma/bcm6348-dma.h | 17 +++++++++++++++++
 2 files changed, 33 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6348-dma.h

diff --git a/arch/mips/dts/brcm,bcm6348.dtsi b/arch/mips/dts/brcm,bcm6348.dtsi
index 92fb91afc1..d774c59665 100644
--- a/arch/mips/dts/brcm,bcm6348.dtsi
+++ b/arch/mips/dts/brcm,bcm6348.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6348-clock.h>
+#include <dt-bindings/dma/bcm6348-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6348-reset.h>
 #include "skeleton.dtsi"
@@ -160,5 +161,20 @@
 			reg = <0xfffe2300 0x38>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller at fffe7000 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe7000 0x1c>,
+			      <0xfffe7100 0x40>,
+			      <0xfffe7200 0x40>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <4>;
+			clocks = <&periph_clk BCM6348_CLK_ENET>;
+			resets = <&periph_rst BCM6348_RST_ENET>,
+				 <&periph_rst BCM6348_RST_DMAMEM>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6348-dma.h b/include/dt-bindings/dma/bcm6348-dma.h
new file mode 100644
index 0000000000..a1d3a6456d
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6348-dma.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6348_H
+#define __DT_BINDINGS_DMA_BCM6348_H
+
+#define BCM6348_DMA_ENET0_RX	0
+#define BCM6348_DMA_ENET0_TX	1
+#define BCM6348_DMA_ENET1_RX	2
+#define BCM6348_DMA_ENET1_TX	3
+
+#endif /* __DT_BINDINGS_DMA_BCM6348_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 06/15] bmips: bcm6358: add bcm6348-iudma support
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (4 preceding siblings ...)
  2018-02-21 16:10   ` [U-Boot] [RFC v3 05/15] bmips: bcm6348: " Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 07/15] phy: add support for internal phys Álvaro Fernández Rojas
                     ` (8 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6358.dtsi       | 18 ++++++++++++++++++
 include/dt-bindings/dma/bcm6358-dma.h | 17 +++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6358-dma.h

diff --git a/arch/mips/dts/brcm,bcm6358.dtsi b/arch/mips/dts/brcm,bcm6358.dtsi
index b63b53baee..1468e4f63a 100644
--- a/arch/mips/dts/brcm,bcm6358.dtsi
+++ b/arch/mips/dts/brcm,bcm6358.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6358-clock.h>
+#include <dt-bindings/dma/bcm6358-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6358-reset.h>
 #include "skeleton.dtsi"
@@ -191,5 +192,22 @@
 
 			status = "disabled";
 		};
+
+		iudma: dma-controller at fffe5000 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe5000 0x24>,
+			      <0xfffe5100 0x80>,
+			      <0xfffe5200 0x80>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <8>;
+			clocks = <&periph_clk BCM6358_CLK_EMUSB>,
+				 <&periph_clk BCM6358_CLK_USBSU>,
+				 <&periph_clk BCM6358_CLK_EPHY>;
+			resets = <&periph_rst BCM6358_RST_ENET>,
+				 <&periph_rst BCM6358_RST_EPHY>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6358-dma.h b/include/dt-bindings/dma/bcm6358-dma.h
new file mode 100644
index 0000000000..3b1fcf8540
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6358-dma.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6358_H
+#define __DT_BINDINGS_DMA_BCM6358_H
+
+#define BCM6358_DMA_ENET0_RX	0
+#define BCM6358_DMA_ENET0_TX	1
+#define BCM6358_DMA_ENET1_RX	2
+#define BCM6358_DMA_ENET1_TX	3
+
+#endif /* __DT_BINDINGS_DMA_BCM6358_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 07/15] phy: add support for internal phys
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (5 preceding siblings ...)
  2018-02-21 16:10   ` [U-Boot] [RFC v3 06/15] bmips: bcm6358: " Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
                     ` (7 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: no changes

 include/phy.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/phy.h b/include/phy.h
index 0543ec10c2..8f3e53db01 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -50,6 +50,7 @@
 
 
 typedef enum {
+	PHY_INTERFACE_MODE_INTERNAL,
 	PHY_INTERFACE_MODE_MII,
 	PHY_INTERFACE_MODE_GMII,
 	PHY_INTERFACE_MODE_SGMII,
@@ -72,6 +73,7 @@ typedef enum {
 } phy_interface_t;
 
 static const char *phy_interface_strings[] = {
+	[PHY_INTERFACE_MODE_INTERNAL]		= "internal",
 	[PHY_INTERFACE_MODE_MII]		= "mii",
 	[PHY_INTERFACE_MODE_GMII]		= "gmii",
 	[PHY_INTERFACE_MODE_SGMII]		= "sgmii",
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 08/15] net: add support for bcm6348-enet
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (6 preceding siblings ...)
  2018-02-21 16:10   ` [U-Boot] [RFC v3 07/15] phy: add support for internal phys Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 09/15] bmips: bcm6338: " Álvaro Fernández Rojas
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: select DMA_CHANNELS.

 drivers/net/Kconfig            |  10 +
 drivers/net/Makefile           |   1 +
 drivers/net/bcm6348-eth.c      | 517 +++++++++++++++++++++++++++++++++++++++++
 include/configs/bmips_common.h |   5 +-
 4 files changed, 532 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/bcm6348-eth.c

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index de1947ccc1..e532332d78 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -71,6 +71,16 @@ config BCM_SF2_ETH_GMAC
 	  by the BCM_SF2_ETH driver.
 	  Say Y to any bcmcygnus based platforms.
 
+config BCM6348_ETH
+	bool "BCM6348 EMAC support"
+	depends on DM_ETH && ARCH_BMIPS
+	select DMA
+	select DMA_CHANNELS
+	select MII
+	select PHYLIB
+	help
+	  This driver supports the BCM6348 Ethernet MAC.
+
 config DWC_ETH_QOS
 	bool "Synopsys DWC Ethernet QOS device support"
 	depends on DM_ETH
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index ac5443c752..282adbc775 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
 obj-$(CONFIG_AG7XXX) += ag7xxx.o
 obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
+obj-$(CONFIG_BCM6348_ETH) += bcm6348-eth.o
 obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
 obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
 obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
diff --git a/drivers/net/bcm6348-eth.c b/drivers/net/bcm6348-eth.c
new file mode 100644
index 0000000000..890b7d5396
--- /dev/null
+++ b/drivers/net/bcm6348-eth.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma.h>
+#include <miiphy.h>
+#include <net.h>
+#include <phy.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+
+#define ETH_ZLEN			60
+
+#define ETH_TX_WATERMARK		32
+#define ETH_MAX_MTU_SIZE		1518
+
+#define ETH_TIMEOUT			100
+
+/* ETH Receiver Configuration register */
+#define ETH_RXCFG_REG			0x00
+#define ETH_RXCFG_ENFLOW_SHIFT		5
+#define ETH_RXCFG_ENFLOW_MASK		(1 << ETH_RXCFG_ENFLOW_SHIFT)
+
+/* ETH Receive Maximum Length register */
+#define ETH_RXMAXLEN_REG		0x04
+#define ETH_RXMAXLEN_SHIFT		0
+#define ETH_RXMAXLEN_MASK		(0x7ff << ETH_RXMAXLEN_SHIFT)
+
+/* ETH Transmit Maximum Length register */
+#define ETH_TXMAXLEN_REG		0x08
+#define ETH_TXMAXLEN_SHIFT		0
+#define ETH_TXMAXLEN_MASK		(0x7ff << ETH_TXMAXLEN_SHIFT)
+
+/* MII Status/Control register */
+#define MII_SC_REG			0x10
+#define MII_SC_MDCFREQDIV_SHIFT		0
+#define MII_SC_MDCFREQDIV_MASK		(0x7f << MII_SC_MDCFREQDIV_SHIFT)
+#define MII_SC_PREAMBLE_EN_SHIFT	7
+#define MII_SC_PREAMBLE_EN_MASK		(1 << MII_SC_PREAMBLE_EN_SHIFT)
+
+/* MII Data register */
+#define MII_DAT_REG			0x14
+#define MII_DAT_DATA_SHIFT		0
+#define MII_DAT_DATA_MASK		(0xffff << MII_DAT_DATA_SHIFT)
+#define MII_DAT_TA_SHIFT		16
+#define MII_DAT_TA_MASK			(0x3 << MII_DAT_TA_SHIFT)
+#define MII_DAT_REG_SHIFT		18
+#define MII_DAT_REG_MASK		(0x1f << MII_DAT_REG_SHIFT)
+#define MII_DAT_PHY_SHIFT		23
+#define MII_DAT_PHY_MASK		(0x1f << MII_DAT_PHY_SHIFT)
+#define MII_DAT_OP_SHIFT		28
+#define MII_DAT_OP_WRITE		(0x5 << MII_DAT_OP_SHIFT)
+#define MII_DAT_OP_READ			(0x6 << MII_DAT_OP_SHIFT)
+
+/* ETH Interrupts Mask register */
+#define ETH_IRMASK_REG			0x18
+
+/* ETH Interrupts register */
+#define ETH_IR_REG			0x1c
+#define ETH_IR_MII_SHIFT		0
+#define ETH_IR_MII_MASK			(1 << ETH_IR_MII_SHIFT)
+
+/* ETH Control register */
+#define ETH_CTL_REG			0x2c
+#define ETH_CTL_ENABLE_SHIFT		0
+#define ETH_CTL_ENABLE_MASK		(1 << ETH_CTL_ENABLE_SHIFT)
+#define ETH_CTL_DISABLE_SHIFT		1
+#define ETH_CTL_DISABLE_MASK		(1 << ETH_CTL_DISABLE_SHIFT)
+#define ETH_CTL_RESET_SHIFT		2
+#define ETH_CTL_RESET_MASK		(1 << ETH_CTL_RESET_SHIFT)
+#define ETH_CTL_EPHY_SHIFT		3
+#define ETH_CTL_EPHY_MASK		(1 << ETH_CTL_EPHY_SHIFT)
+
+/* ETH Transmit Control register */
+#define ETH_TXCTL_REG			0x30
+#define ETH_TXCTL_FD_SHIFT		0
+#define ETH_TXCTL_FD_MASK		(1 << ETH_TXCTL_FD_SHIFT)
+
+/* ETH Transmit Watermask register */
+#define ETH_TXWMARK_REG			0x34
+#define ETH_TXWMARK_WM_SHIFT		0
+#define ETH_TXWMARK_WM_MASK		(0x3f << ETH_TXWMARK_WM_SHIFT)
+
+/* MIB Control register */
+#define MIB_CTL_REG			0x38
+#define MIB_CTL_RDCLEAR_SHIFT		0
+#define MIB_CTL_RDCLEAR_MASK		(1 << MIB_CTL_RDCLEAR_SHIFT)
+
+/* ETH Perfect Match registers */
+#define ETH_PM_CNT			4
+#define ETH_PML_REG(x)			(0x58 + (x) * 0x8)
+#define ETH_PMH_REG(x)			(0x5c + (x) * 0x8)
+#define ETH_PMH_VALID_SHIFT		16
+#define ETH_PMH_VALID_MASK		(1 << ETH_PMH_VALID_SHIFT)
+
+/* MIB Counters registers */
+#define MIB_REG_CNT			55
+#define MIB_REG(x)			(0x200 + (x) * 4)
+
+/* ETH data */
+struct bcm6348_eth_priv {
+	void __iomem *base;
+	/* DMA */
+	struct dma rx_dma;
+	struct dma tx_dma;
+	/* PHY */
+	int phy_id;
+	struct phy_device *phy_dev;
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void bcm6348_eth_mac_disable(struct bcm6348_eth_priv *priv)
+{
+	/* disable emac */
+	clrsetbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK,
+			ETH_CTL_DISABLE_MASK);
+
+	/* wait until emac is disabled */
+	if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
+			      ETH_CTL_DISABLE_MASK, false,
+			      ETH_TIMEOUT, false))
+		pr_err("error disabling emac\n");
+}
+
+static void bcm6348_eth_mac_enable(struct bcm6348_eth_priv *priv)
+{
+	setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK);
+}
+
+static void bcm6348_eth_mac_reset(struct bcm6348_eth_priv *priv)
+{
+	/* reset emac */
+	writel_be(ETH_CTL_RESET_MASK, priv->base + ETH_CTL_REG);
+	wmb();
+
+	/* wait until emac is reset */
+	if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
+			      ETH_CTL_RESET_MASK, false,
+			      ETH_TIMEOUT, false))
+		pr_err("error resetting emac\n");
+}
+
+static int bcm6348_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	return dma_receive(&priv->rx_dma, (void *)packetp);
+}
+
+static int bcm6348_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	length = max(length, ETH_ZLEN);
+
+	return dma_send(&priv->tx_dma, (void **)packet, length);
+}
+
+static int bcm6348_eth_adjust_link(struct udevice *dev,
+				   struct phy_device *phydev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* mac duplex parameters */
+	if (phydev->duplex)
+		setbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
+	else
+		clrbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
+
+	/* rx flow control (pause frame handling) */
+	if (phydev->pause)
+		setbits_be32(priv->base + ETH_RXCFG_REG,
+			     ETH_RXCFG_ENFLOW_MASK);
+	else
+		clrbits_be32(priv->base + ETH_RXCFG_REG,
+			     ETH_RXCFG_ENFLOW_MASK);
+
+	return 0;
+}
+
+static int bcm6348_eth_start(struct udevice *dev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	int ret, i;
+
+	/* enable dma rx channel */
+	dma_enable(&priv->rx_dma);
+
+	/* enable dma tx channel */
+	dma_enable(&priv->tx_dma);
+
+	ret = phy_startup(priv->phy_dev);
+	if (ret) {
+		pr_err("could not initialize phy\n");
+		return ret;
+	}
+
+	if (!priv->phy_dev->link) {
+		pr_err("no phy link\n");
+		return -EIO;
+	}
+
+	bcm6348_eth_adjust_link(dev, priv->phy_dev);
+
+	/* zero mib counters */
+	for (i = 0; i < MIB_REG_CNT; i++)
+		writel_be(0, MIB_REG(i));
+
+	/* enable rx flow control */
+	setbits_be32(priv->base + ETH_RXCFG_REG, ETH_RXCFG_ENFLOW_MASK);
+
+	/* set max rx/tx length */
+	writel_be((ETH_MAX_MTU_SIZE << ETH_RXMAXLEN_SHIFT) &
+		  ETH_RXMAXLEN_MASK, priv->base + ETH_RXMAXLEN_REG);
+	writel_be((ETH_MAX_MTU_SIZE << ETH_TXMAXLEN_SHIFT) &
+		   ETH_TXMAXLEN_MASK, priv->base + ETH_TXMAXLEN_REG);
+
+	/* set correct transmit fifo watermark */
+	writel_be((ETH_TX_WATERMARK << ETH_TXWMARK_WM_SHIFT) &
+		  ETH_TXWMARK_WM_MASK, priv->base + ETH_TXWMARK_REG);
+
+	/* enable emac */
+	bcm6348_eth_mac_enable(priv);
+
+	/* clear interrupts */
+	writel_be(0, priv->base + ETH_IRMASK_REG);
+
+	return 0;
+}
+
+static void bcm6348_eth_stop(struct udevice *dev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* disable dma rx channel */
+	dma_disable(&priv->rx_dma);
+
+	/* disable dma tx channel */
+	dma_disable(&priv->tx_dma);
+
+	/* disable emac */
+	bcm6348_eth_mac_disable(priv);
+}
+
+static int bcm6348_eth_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	bool running = false;
+
+	/* check if emac is running */
+	if (readl_be(priv->base + ETH_CTL_REG) & ETH_CTL_ENABLE_MASK)
+		running = true;
+
+	/* disable emac */
+	if (running)
+		bcm6348_eth_mac_disable(priv);
+
+	/* set mac address */
+	writel_be((pdata->enetaddr[2] << 24) | (pdata->enetaddr[3]) << 16 |
+		  (pdata->enetaddr[4]) << 8 | (pdata->enetaddr[5]),
+		  priv->base + ETH_PML_REG(0));
+	writel_be((pdata->enetaddr[1]) | (pdata->enetaddr[0] << 8) |
+		  ETH_PMH_VALID_MASK, priv->base + ETH_PMH_REG(0));
+
+	/* enable emac */
+	if (running)
+		bcm6348_eth_mac_enable(priv);
+
+	return 0;
+}
+
+static const struct eth_ops bcm6348_eth_ops = {
+	.recv = bcm6348_eth_recv,
+	.send = bcm6348_eth_send,
+	.start = bcm6348_eth_start,
+	.stop = bcm6348_eth_stop,
+	.write_hwaddr = bcm6348_eth_write_hwaddr,
+};
+
+static const struct udevice_id bcm6348_eth_ids[] = {
+	{ .compatible = "brcm,bcm6348-enet", },
+	{ /* sentinel */ }
+};
+
+static int bcm6348_mdio_op(void __iomem *base, uint32_t data)
+{
+	/* make sure mii interrupt status is cleared */
+	writel_be(ETH_IR_MII_MASK, base + ETH_IR_REG);
+
+	/* issue mii op */
+	writel_be(data, base + MII_DAT_REG);
+
+	/* wait until emac is disabled */
+	return wait_for_bit_be32(base + ETH_IR_REG,
+				 ETH_IR_MII_MASK, true,
+				 ETH_TIMEOUT, false);
+}
+
+static int bcm6348_mdio_read(struct mii_dev *bus, int addr, int devaddr,
+			     int reg)
+{
+	void __iomem *base = bus->priv;
+	uint32_t val;
+
+	val = MII_DAT_OP_READ;
+	val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
+	val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
+	val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
+
+	if (bcm6348_mdio_op(base, val)) {
+		pr_err("%s: timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	val = readl_be(base + MII_DAT_REG) & MII_DAT_DATA_MASK;
+	val >>= MII_DAT_DATA_SHIFT;
+
+	return val;
+}
+
+static int bcm6348_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
+			      int reg, u16 value)
+{
+	void __iomem *base = bus->priv;
+	uint32_t val;
+
+	val = MII_DAT_OP_WRITE;
+	val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
+	val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
+	val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
+	val |= (value << MII_DAT_DATA_SHIFT) & MII_DAT_DATA_MASK;
+
+	if (bcm6348_mdio_op(base, val)) {
+		pr_err("%s: timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int bcm6348_mdio_init(const char *name, void __iomem *base)
+{
+	struct mii_dev *bus;
+
+	bus = mdio_alloc();
+	if (!bus) {
+		pr_err("%s: failed to allocate MDIO bus\n", __func__);
+		return -ENOMEM;
+	}
+
+	bus->read = bcm6348_mdio_read;
+	bus->write = bcm6348_mdio_write;
+	bus->priv = base;
+	snprintf(bus->name, sizeof(bus->name), "%s", name);
+
+	return mdio_register(bus);
+}
+
+static int bcm6348_phy_init(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	struct mii_dev *bus;
+
+	/* get mii bus */
+	bus = miiphy_get_dev_by_name(dev->name);
+
+	/* phy connect */
+	priv->phy_dev = phy_connect(bus, priv->phy_id, dev,
+				    pdata->phy_interface);
+	if (!priv->phy_dev) {
+		pr_err("%s: no phy device\n", __func__);
+		return -ENODEV;
+	}
+
+	priv->phy_dev->supported = (SUPPORTED_10baseT_Half |
+				    SUPPORTED_10baseT_Full |
+				    SUPPORTED_100baseT_Half |
+				    SUPPORTED_100baseT_Full |
+				    SUPPORTED_Autoneg |
+				    SUPPORTED_Pause |
+				    SUPPORTED_MII);
+	priv->phy_dev->advertising = priv->phy_dev->supported;
+
+	/* phy config */
+	phy_config(priv->phy_dev);
+
+	return 0;
+}
+
+static int bcm6348_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	void *blob = (void *)gd->fdt_blob;
+	int node = dev_of_offset(dev);
+	const char *phy_mode;
+	fdt_addr_t addr;
+	int phy_node, ret, i;
+
+	/* get base address */
+	addr = devfdt_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	/* get phy mode */
+	pdata->phy_interface = PHY_INTERFACE_MODE_NONE;
+	phy_mode = fdt_getprop(blob, node, "phy-mode", NULL);
+	if (phy_mode)
+		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_NONE)
+		return -ENODEV;
+
+	/* get phy */
+	phy_node = fdtdec_lookup_phandle(blob, node, "phy");
+	if (phy_node >= 0)
+		priv->phy_id = fdtdec_get_int(blob, phy_node, "reg", -1);
+	else
+		return -EINVAL;
+
+	/* get dma channels */
+	ret = dma_get_by_name(dev, "tx", &priv->tx_dma);
+	if (ret)
+		return -EINVAL;
+
+	ret = dma_get_by_name(dev, "rx", &priv->rx_dma);
+	if (ret)
+		return -EINVAL;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+		if (clk_enable(&clk))
+			pr_err("failed to enable clock %d\n", i);
+		clk_free(&clk);
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+		if (reset_deassert(&reset))
+			pr_err("failed to deassert reset %d\n", i);
+		reset_free(&reset);
+	}
+
+	/* get base addr */
+	priv->base = ioremap(addr, 0);
+	pdata->iobase = (phys_addr_t) priv->base;
+
+	/* disable emac */
+	bcm6348_eth_mac_disable(priv);
+
+	/* reset emac */
+	bcm6348_eth_mac_reset(priv);
+
+	/* select correct mii interface */
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_INTERNAL)
+		clrbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
+	else
+		setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
+
+	/* turn on mdc clock */
+	writel_be((0x1f << MII_SC_MDCFREQDIV_SHIFT) |
+		  MII_SC_PREAMBLE_EN_MASK, priv->base + MII_SC_REG);
+
+	/* set mib counters to not clear when read */
+	clrbits_be32(priv->base + MIB_CTL_REG, MIB_CTL_RDCLEAR_MASK);
+
+	/* initialize perfect match registers */
+	for (i = 0; i < ETH_PM_CNT; i++) {
+		writel_be(0, priv->base + ETH_PML_REG(i));
+		writel_be(0, priv->base + ETH_PMH_REG(i));
+	}
+
+	/* init mii bus */
+	ret = bcm6348_mdio_init(dev->name, priv->base);
+	if (ret)
+		return ret;
+
+	/* init phy */
+	ret = bcm6348_phy_init(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_eth) = {
+	.name = "bcm6348_eth",
+	.id = UCLASS_ETH,
+	.of_match = bcm6348_eth_ids,
+	.ops = &bcm6348_eth_ops,
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.priv_auto_alloc_size = sizeof(struct bcm6348_eth_priv),
+	.probe = bcm6348_eth_probe,
+};
diff --git a/include/configs/bmips_common.h b/include/configs/bmips_common.h
index 38bf7a272b..eb66512f67 100644
--- a/include/configs/bmips_common.h
+++ b/include/configs/bmips_common.h
@@ -7,6 +7,9 @@
 #ifndef __CONFIG_BMIPS_COMMON_H
 #define __CONFIG_BMIPS_COMMON_H
 
+/* ETH */
+#define CONFIG_PHY_RESET_DELAY		20
+
 /* UART */
 #define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200, \
 					  230400, 500000, 1500000 }
@@ -17,7 +20,7 @@
 
 /* Memory usage */
 #define CONFIG_SYS_MAXARGS		24
-#define CONFIG_SYS_MALLOC_LEN		(1024 * 1024)
+#define CONFIG_SYS_MALLOC_LEN		(2 * 1024 * 1024)
 #define CONFIG_SYS_BOOTPARAMS_LEN	(128 * 1024)
 #define CONFIG_SYS_CBSIZE		512
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 09/15] bmips: bcm6338: add support for bcm6348-enet
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (7 preceding siblings ...)
  2018-02-21 16:10   ` [U-Boot] [RFC v3 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 10/15] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6338.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6338.dtsi b/arch/mips/dts/brcm,bcm6338.dtsi
index 4125f71d9f..621278c9d1 100644
--- a/arch/mips/dts/brcm,bcm6338.dtsi
+++ b/arch/mips/dts/brcm,bcm6338.dtsi
@@ -145,5 +145,20 @@
 			dma-channels = <6>;
 			resets = <&periph_rst BCM6338_RST_DMAMEM>;
 		};
+
+		enet: ethernet at fffe2800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe2800 0x2dc>;
+			clocks = <&periph_clk BCM6338_CLK_ENET>;
+			resets = <&periph_rst BCM6338_RST_ENET>;
+			dmas = <&iudma BCM6338_DMA_ENET_RX>,
+			       <&iudma BCM6338_DMA_ENET_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
 	};
 };
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 10/15] bmips: enable f@st1704 enet support
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (8 preceding siblings ...)
  2018-02-21 16:10   ` [U-Boot] [RFC v3 09/15] bmips: bcm6338: " Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 11/15] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: no changes

 arch/mips/dts/sagem,f at st1704.dts     | 12 ++++++++++++
 configs/sagem_f at st1704_ram_defconfig |  9 ++++++++-
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/sagem,f at st1704.dts b/arch/mips/dts/sagem,f at st1704.dts
index dd0e5b8b7c..99d031f10a 100644
--- a/arch/mips/dts/sagem,f at st1704.dts
+++ b/arch/mips/dts/sagem,f at st1704.dts
@@ -40,6 +40,18 @@
 	};
 };
 
+&enet {
+	status = "okay";
+	phy = <&enetphy>;
+	phy-mode = "mii";
+
+	enetphy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio {
 	status = "okay";
 };
diff --git a/configs/sagem_f at st1704_ram_defconfig b/configs/sagem_f at st1704_ram_defconfig
index 0adcd46d51..1a640781b7 100644
--- a/configs/sagem_f at st1704_ram_defconfig
+++ b/configs/sagem_f at st1704_ram_defconfig
@@ -28,11 +28,15 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_SF=y
 CONFIG_CMD_SPI=y
-# CONFIG_CMD_NET is not set
+CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -41,6 +45,9 @@ CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_DM_RESET=y
 CONFIG_RESET_BCM6345=y
 # CONFIG_SPL_SERIAL_PRESENT is not set
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 11/15] bmips: bcm6348: add support for bcm6348-enet
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (9 preceding siblings ...)
  2018-02-21 16:10   ` [U-Boot] [RFC v3 10/15] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 12/15] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6348.dtsi | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6348.dtsi b/arch/mips/dts/brcm,bcm6348.dtsi
index d774c59665..e540865019 100644
--- a/arch/mips/dts/brcm,bcm6348.dtsi
+++ b/arch/mips/dts/brcm,bcm6348.dtsi
@@ -162,6 +162,32 @@
 			u-boot,dm-pre-reloc;
 		};
 
+		enet0: ethernet at fffe6000 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe6000 0x2dc>;
+			dmas = <&iudma BCM6348_DMA_ENET0_RX>,
+			       <&iudma BCM6348_DMA_ENET0_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		enet1: ethernet at fffe6800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe6800 0x2dc>;
+			dmas = <&iudma BCM6348_DMA_ENET1_RX>,
+			       <&iudma BCM6348_DMA_ENET1_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
 		iudma: dma-controller at fffe7000 {
 			compatible = "brcm,bcm6348-iudma";
 			reg = <0xfffe7000 0x1c>,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 12/15] bmips: enable ct-5361 enet support
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (10 preceding siblings ...)
  2018-02-21 16:10   ` [U-Boot] [RFC v3 11/15] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 13/15] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: no changes

 arch/mips/dts/comtrend,ct-5361.dts    | 12 ++++++++++++
 configs/comtrend_ct5361_ram_defconfig |  8 +++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/comtrend,ct-5361.dts b/arch/mips/dts/comtrend,ct-5361.dts
index 74dc09046c..a78aa877fc 100644
--- a/arch/mips/dts/comtrend,ct-5361.dts
+++ b/arch/mips/dts/comtrend,ct-5361.dts
@@ -35,6 +35,18 @@
 	};
 };
 
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/comtrend_ct5361_ram_defconfig b/configs/comtrend_ct5361_ram_defconfig
index 8b842606f5..0737772dd2 100644
--- a/configs/comtrend_ct5361_ram_defconfig
+++ b/configs/comtrend_ct5361_ram_defconfig
@@ -26,11 +26,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -38,6 +41,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6348_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 13/15] bmips: bcm6358: add support for bcm6348-enet
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (11 preceding siblings ...)
  2018-02-21 16:10   ` [U-Boot] [RFC v3 12/15] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 14/15] bmips: enable hg556a enet support Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 15/15] bmips: enable nb4-ser " Álvaro Fernández Rojas
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6358.dtsi | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6358.dtsi b/arch/mips/dts/brcm,bcm6358.dtsi
index 1468e4f63a..04329864c2 100644
--- a/arch/mips/dts/brcm,bcm6358.dtsi
+++ b/arch/mips/dts/brcm,bcm6358.dtsi
@@ -193,6 +193,34 @@
 			status = "disabled";
 		};
 
+		enet0: ethernet at fffe4000 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe4000 0x2dc>;
+			clocks = <&periph_clk BCM6358_CLK_ENET0>;
+			dmas = <&iudma BCM6358_DMA_ENET0_RX>,
+			       <&iudma BCM6358_DMA_ENET0_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		enet1: ethernet at fffe4800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe4800 0x2dc>;
+			clocks = <&periph_clk BCM6358_CLK_ENET1>;
+			dmas = <&iudma BCM6358_DMA_ENET1_RX>,
+			       <&iudma BCM6358_DMA_ENET1_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
 		iudma: dma-controller at fffe5000 {
 			compatible = "brcm,bcm6348-iudma";
 			reg = <0xfffe5000 0x24>,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 14/15] bmips: enable hg556a enet support
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (12 preceding siblings ...)
  2018-02-21 16:10   ` [U-Boot] [RFC v3 13/15] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  2018-02-21 16:10   ` [U-Boot] [RFC v3 15/15] bmips: enable nb4-ser " Álvaro Fernández Rojas
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: no changes

 arch/mips/dts/huawei,hg556a.dts     | 12 ++++++++++++
 configs/huawei_hg556a_ram_defconfig |  8 +++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/huawei,hg556a.dts b/arch/mips/dts/huawei,hg556a.dts
index a1e9c15ab9..2f99e0905c 100644
--- a/arch/mips/dts/huawei,hg556a.dts
+++ b/arch/mips/dts/huawei,hg556a.dts
@@ -94,6 +94,18 @@
 	status = "okay";
 };
 
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/huawei_hg556a_ram_defconfig b/configs/huawei_hg556a_ram_defconfig
index 7f7f34ed61..c7c7c6554f 100644
--- a/configs/huawei_hg556a_ram_defconfig
+++ b/configs/huawei_hg556a_ram_defconfig
@@ -26,11 +26,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -38,6 +41,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6358_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 15/15] bmips: enable nb4-ser enet support
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (13 preceding siblings ...)
  2018-02-21 16:10   ` [U-Boot] [RFC v3 14/15] bmips: enable hg556a enet support Álvaro Fernández Rojas
@ 2018-02-21 16:10   ` Álvaro Fernández Rojas
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-21 16:10 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v3: no changes
 v2: no changes

 arch/mips/dts/sfr,nb4-ser.dts     | 24 ++++++++++++++++++++++++
 configs/sfr_nb4-ser_ram_defconfig |  8 +++++++-
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/sfr,nb4-ser.dts b/arch/mips/dts/sfr,nb4-ser.dts
index 473372faa1..73db45f9ea 100644
--- a/arch/mips/dts/sfr,nb4-ser.dts
+++ b/arch/mips/dts/sfr,nb4-ser.dts
@@ -54,6 +54,30 @@
 	status = "okay";
 };
 
+&enet0 {
+	status = "okay";
+	phy = <&enet0phy>;
+	phy-mode = "internal";
+
+	enet0phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/sfr_nb4-ser_ram_defconfig b/configs/sfr_nb4-ser_ram_defconfig
index fc323d879d..07b49a1a77 100644
--- a/configs/sfr_nb4-ser_ram_defconfig
+++ b/configs/sfr_nb4-ser_ram_defconfig
@@ -27,11 +27,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -40,6 +43,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6358_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 01/15] dma: move dma_ops to dma-uclass.h
  2018-02-21 16:10   ` [U-Boot] [RFC v3 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
@ 2018-02-22 16:18     ` Simon Glass
  2018-03-05 19:35       ` Grygorii Strashko
  0 siblings, 1 reply; 106+ messages in thread
From: Simon Glass @ 2018-02-22 16:18 UTC (permalink / raw)
  To: u-boot

On 21 February 2018 at 09:10, Álvaro Fernández Rojas <noltari@gmail.com> wrote:
> Move dma_ops to a separate header file, following other uclass implementations.
> While doing so, this patch also improves dma_ops documentation.
>
> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
> ---
>  v3: Introduce changes reported by Simon Glass:
>   - Improve dma-uclass.h documentation.
>   - Switch to live tree API.
>
>  drivers/dma/dma-uclass.c |  3 ++-
>  include/dma-uclass.h     | 39 +++++++++++++++++++++++++++++++++++++++
>  include/dma.h            | 22 ----------------------
>  3 files changed, 41 insertions(+), 23 deletions(-)
>  create mode 100644 include/dma-uclass.h

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 02/15] dma: add channels support
  2018-02-21 16:10   ` [U-Boot] [RFC v3 02/15] dma: add channels support Álvaro Fernández Rojas
@ 2018-02-22 16:18     ` Simon Glass
  0 siblings, 0 replies; 106+ messages in thread
From: Simon Glass @ 2018-02-22 16:18 UTC (permalink / raw)
  To: u-boot

On 21 February 2018 at 09:10, Álvaro Fernández Rojas <noltari@gmail.com> 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 <noltari@gmail.com>
> ---
>  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(-)
>

Reviewed-by: Simon Glass <sjg@chromium.org>

Re moving the code into ofdata_to_platdata(), I suppose what you have
here is OK.

Regards,
Simon

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 03/15] dma: add bcm6348-iudma support
  2018-02-21 16:10   ` [U-Boot] [RFC v3 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
@ 2018-02-22 19:50     ` Grygorii Strashko
  2018-02-22 20:48       ` Álvaro Fernández Rojas
  0 siblings, 1 reply; 106+ messages in thread
From: Grygorii Strashko @ 2018-02-22 19:50 UTC (permalink / raw)
  To: u-boot

Hi 

I'd appreciated if you can clarify few points below.

On 02/21/2018 10:10 AM, Álvaro Fernández Rojas wrote:
> BCM6348 IUDMA controller is present on multiple BMIPS (BCM63xx) SoCs.
> 
> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
> ---
>   v3: no changes
>   v2: Fix dma rx burst config and select DMA_CHANNELS.
> 
>   drivers/dma/Kconfig         |   9 +
>   drivers/dma/Makefile        |   1 +
>   drivers/dma/bcm6348-iudma.c | 505 ++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 515 insertions(+)
>   create mode 100644 drivers/dma/bcm6348-iudma.c
>

[...]
 
>
> +static int bcm6348_iudma_enable(struct dma *dma)
> +{
> +	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
> +	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
> +	struct bcm6348_dma_desc *dma_desc;
> +	uint8_t i;
> +
> +	/* init dma rings */
> +	dma_desc = ch_priv->dma_ring;
> +	for (i = 0; i < ch_priv->dma_ring_size; i++) {
> +		if (bcm6348_iudma_chan_is_rx(dma->id)) {
> +			dma_desc->status = DMAD_ST_OWN_MASK;
> +			dma_desc->length = PKTSIZE_ALIGN;
> +			dma_desc->address = virt_to_phys(net_rx_packets[i]);

You are filling RX queue/ring with buffers defined in Net core.
Does it mean that this DMA driver will not be usable for other purposes, as
Net can be compiled out?

Wouldn't it be reasonable to have some sort of .receive_prepare() callback in
DMA dma_ops, so DMA user can control which buffers to push in RX DMA channel?
And it also can be used in eth_ops.free_pkt() callback (see below).

> +		} else {
> +			dma_desc->status = 0;
> +			dma_desc->length = 0;
> +			dma_desc->address = 0;
> +		}
> +
> +		if (i == ch_priv->dma_ring_size - 1)
> +			dma_desc->status |= DMAD_ST_WRAP_MASK;
> +
> +		if (bcm6348_iudma_chan_is_rx(dma->id))
> +			writel_be(1,
> +				  priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
> +
> +		dma_desc++;
> +	}
> +
> +	/* init to first descriptor */
> +	ch_priv->desc_id = 0;
> +
> +	/* force cache writeback */
> +	flush_dcache_range((ulong)ch_priv->dma_ring,
> +		ALIGN_END_ADDR(struct bcm6348_dma_desc, ch_priv->dma_ring,
> +			       ch_priv->dma_ring_size));
> +
> +	/* clear sram */
> +	writel_be(0, priv->sram + DMAS_STATE_DATA_REG(dma->id));
> +	writel_be(0, priv->sram + DMAS_DESC_LEN_STATUS_REG(dma->id));
> +	writel_be(0, priv->sram + DMAS_DESC_BASE_BUFPTR_REG(dma->id));
> +
> +	/* set dma ring start */
> +	writel_be(virt_to_phys(ch_priv->dma_ring),
> +		  priv->sram + DMAS_RSTART_REG(dma->id));
> +
> +	/* set flow control */
> +	if (bcm6348_iudma_chan_is_rx(dma->id)) {
> +		u32 val;
> +
> +		setbits_be32(priv->base + DMA_CFG_REG,
> +			     DMA_CFG_FLOWC_ENABLE(dma->id));
> +
> +		val = ch_priv->dma_ring_size / 3;
> +		writel_be(val, priv->base + DMA_FLOWC_THR_LO_REG(dma->id));
> +
> +		val = (ch_priv->dma_ring_size * 2) / 3;
> +		writel_be(val, priv->base + DMA_FLOWC_THR_HI_REG(dma->id));
> +	}
> +
> +	/* set dma max burst */
> +	writel_be(ch_priv->dma_ring_size,
> +		  priv->chan + DMAC_BURST_REG(dma->id));
> +
> +	/* clear interrupts */
> +	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_ST_REG(dma->id));
> +	writel_be(0, priv->chan + DMAC_IR_EN_REG(dma->id));
> +
> +	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
> +
> +	return 0;
> +}

[...]

> +
> +static int bcm6348_iudma_receive(struct dma *dma, void **dst)
> +{
> +	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
> +	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
> +	struct bcm6348_dma_desc *dma_desc;
> +	void __iomem *dma_buff;
> +	uint16_t status;
> +	int ret;
> +
> +	/* get dma ring descriptor address */
> +	dma_desc = ch_priv->dma_ring;
> +	dma_desc += ch_priv->desc_id;
> +
> +	/* invalidate cache data */
> +	invalidate_dcache_range((ulong)dma_desc,
> +		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
> +
> +	/* check dma own */
> +	if (dma_desc->status & DMAD_ST_OWN_MASK)
> +		return 0;
> +
> +	/* check dma end */
> +	if (!(dma_desc->status & DMAD_ST_EOP_MASK))
> +		return -EINVAL;
> +
> +	/* get dma buff descriptor address */
> +	dma_buff = phys_to_virt(dma_desc->address);
> +
> +	/* invalidate cache data */
> +	invalidate_dcache_range((ulong)dma_buff,
> +				(ulong)(dma_buff + PKTSIZE_ALIGN));
> +
> +	/* get dma data */
> +	*dst = dma_buff;
> +	ret = dma_desc->length;
> +
> +	/* reinit dma descriptor */
> +	status = dma_desc->status & DMAD_ST_WRAP_MASK;
> +	status |= DMAD_ST_OWN_MASK;
> +
> +	dma_desc->length = PKTSIZE_ALIGN;
> +	dma_desc->status = status;
> +
> +	/* flush cache */
> +	flush_dcache_range((ulong)dma_desc,
> +		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));

Could you clarify pls, if you do return dma_desc to RX ring here or not?

if yes, wouldn't it cause potential problem on Net RX path 
		ret = eth_get_ops(current)->recv(current, flags, &packet);
^^ (1) here buffer will be received from DMA ( and pushed back to RX ring ?? )

		flags = 0;
		if (ret > 0)
			net_process_received_packet(packet, ret);
^^ (2) here it will be passed in Net stack

		if (ret >= 0 && eth_get_ops(current)->free_pkt)
			eth_get_ops(current)->free_pkt(current, packet, ret);
^^ at this point it should be safe to return buffer in DMA RX ring.

		if (ret <= 0)
			break;

Can DMA overwrite packet after point (1) while packet is still processed (2)?

> +
> +	/* set flow control buffer alloc */
> +	writel_be(1, priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
> +
> +	/* enable dma */
> +	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
> +
> +	/* set interrupt */
> +	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_EN_REG(dma->id));
> +
> +	/* increment dma descriptor */
> +	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->dma_ring_size;
> +
> +	return ret - 4;
> +}
> +



-- 
regards,
-grygorii

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 03/15] dma: add bcm6348-iudma support
  2018-02-22 19:50     ` Grygorii Strashko
@ 2018-02-22 20:48       ` Álvaro Fernández Rojas
  2018-02-23 16:57         ` Grygorii Strashko
  0 siblings, 1 reply; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-02-22 20:48 UTC (permalink / raw)
  To: u-boot

Hi Grygori,

El 22/02/2018 a las 20:50, Grygorii Strashko escribió:
> Hi
>
> I'd appreciated if you can clarify few points below.
>
> On 02/21/2018 10:10 AM, Álvaro Fernández Rojas wrote:
>> BCM6348 IUDMA controller is present on multiple BMIPS (BCM63xx) SoCs.
>>
>> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
>> ---
>>    v3: no changes
>>    v2: Fix dma rx burst config and select DMA_CHANNELS.
>>
>>    drivers/dma/Kconfig         |   9 +
>>    drivers/dma/Makefile        |   1 +
>>    drivers/dma/bcm6348-iudma.c | 505 ++++++++++++++++++++++++++++++++++++++++++++
>>    3 files changed, 515 insertions(+)
>>    create mode 100644 drivers/dma/bcm6348-iudma.c
>>
> [...]
>   
>> +static int bcm6348_iudma_enable(struct dma *dma)
>> +{
>> +	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
>> +	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
>> +	struct bcm6348_dma_desc *dma_desc;
>> +	uint8_t i;
>> +
>> +	/* init dma rings */
>> +	dma_desc = ch_priv->dma_ring;
>> +	for (i = 0; i < ch_priv->dma_ring_size; i++) {
>> +		if (bcm6348_iudma_chan_is_rx(dma->id)) {
>> +			dma_desc->status = DMAD_ST_OWN_MASK;
>> +			dma_desc->length = PKTSIZE_ALIGN;
>> +			dma_desc->address = virt_to_phys(net_rx_packets[i]);
> You are filling RX queue/ring with buffers defined in Net core.
> Does it mean that this DMA driver will not be usable for other purposes, as
> Net can be compiled out?
As far as I know, and depending on the specific SoC, BCM63xx IUDMA is 
used for Ethernet, USB (device only) and xDSL.
So yes, in u-boot it will be used for ethernet only.
BTW, my first attempt didn't use net_rx_packets, but I saw that in 
pic32_eth implementation and dropped the dma specific buffers. I will 
add them again ;).
>
> Wouldn't it be reasonable to have some sort of .receive_prepare() callback in
> DMA dma_ops, so DMA user can control which buffers to push in RX DMA channel?
> And it also can be used in eth_ops.free_pkt() callback (see below).
Yes, probably, but maybe we can achieve that without adding another call.
>
>> +		} else {
>> +			dma_desc->status = 0;
>> +			dma_desc->length = 0;
>> +			dma_desc->address = 0;
>> +		}
>> +
>> +		if (i == ch_priv->dma_ring_size - 1)
>> +			dma_desc->status |= DMAD_ST_WRAP_MASK;
>> +
>> +		if (bcm6348_iudma_chan_is_rx(dma->id))
>> +			writel_be(1,
>> +				  priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
>> +
>> +		dma_desc++;
>> +	}
>> +
>> +	/* init to first descriptor */
>> +	ch_priv->desc_id = 0;
>> +
>> +	/* force cache writeback */
>> +	flush_dcache_range((ulong)ch_priv->dma_ring,
>> +		ALIGN_END_ADDR(struct bcm6348_dma_desc, ch_priv->dma_ring,
>> +			       ch_priv->dma_ring_size));
>> +
>> +	/* clear sram */
>> +	writel_be(0, priv->sram + DMAS_STATE_DATA_REG(dma->id));
>> +	writel_be(0, priv->sram + DMAS_DESC_LEN_STATUS_REG(dma->id));
>> +	writel_be(0, priv->sram + DMAS_DESC_BASE_BUFPTR_REG(dma->id));
>> +
>> +	/* set dma ring start */
>> +	writel_be(virt_to_phys(ch_priv->dma_ring),
>> +		  priv->sram + DMAS_RSTART_REG(dma->id));
>> +
>> +	/* set flow control */
>> +	if (bcm6348_iudma_chan_is_rx(dma->id)) {
>> +		u32 val;
>> +
>> +		setbits_be32(priv->base + DMA_CFG_REG,
>> +			     DMA_CFG_FLOWC_ENABLE(dma->id));
>> +
>> +		val = ch_priv->dma_ring_size / 3;
>> +		writel_be(val, priv->base + DMA_FLOWC_THR_LO_REG(dma->id));
>> +
>> +		val = (ch_priv->dma_ring_size * 2) / 3;
>> +		writel_be(val, priv->base + DMA_FLOWC_THR_HI_REG(dma->id));
>> +	}
>> +
>> +	/* set dma max burst */
>> +	writel_be(ch_priv->dma_ring_size,
>> +		  priv->chan + DMAC_BURST_REG(dma->id));
>> +
>> +	/* clear interrupts */
>> +	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_ST_REG(dma->id));
>> +	writel_be(0, priv->chan + DMAC_IR_EN_REG(dma->id));
>> +
>> +	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
>> +
>> +	return 0;
>> +}
> [...]
>
>> +
>> +static int bcm6348_iudma_receive(struct dma *dma, void **dst)
>> +{
>> +	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
>> +	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
>> +	struct bcm6348_dma_desc *dma_desc;
>> +	void __iomem *dma_buff;
>> +	uint16_t status;
>> +	int ret;
>> +
>> +	/* get dma ring descriptor address */
>> +	dma_desc = ch_priv->dma_ring;
>> +	dma_desc += ch_priv->desc_id;
>> +
>> +	/* invalidate cache data */
>> +	invalidate_dcache_range((ulong)dma_desc,
>> +		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
>> +
>> +	/* check dma own */
>> +	if (dma_desc->status & DMAD_ST_OWN_MASK)
>> +		return 0;
>> +
>> +	/* check dma end */
>> +	if (!(dma_desc->status & DMAD_ST_EOP_MASK))
>> +		return -EINVAL;
>> +
>> +	/* get dma buff descriptor address */
>> +	dma_buff = phys_to_virt(dma_desc->address);
>> +
>> +	/* invalidate cache data */
>> +	invalidate_dcache_range((ulong)dma_buff,
>> +				(ulong)(dma_buff + PKTSIZE_ALIGN));
>> +
>> +	/* get dma data */
>> +	*dst = dma_buff;
>> +	ret = dma_desc->length;
>> +
>> +	/* reinit dma descriptor */
>> +	status = dma_desc->status & DMAD_ST_WRAP_MASK;
>> +	status |= DMAD_ST_OWN_MASK;
>> +
>> +	dma_desc->length = PKTSIZE_ALIGN;
>> +	dma_desc->status = status;
>> +
>> +	/* flush cache */
>> +	flush_dcache_range((ulong)dma_desc,
>> +		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
> Could you clarify pls, if you do return dma_desc to RX ring here or not?
Yes.
>
> if yes, wouldn't it cause potential problem on Net RX path
> 		ret = eth_get_ops(current)->recv(current, flags, &packet);
> ^^ (1) here buffer will be received from DMA ( and pushed back to RX ring ?? )
>
> 		flags = 0;
> 		if (ret > 0)
> 			net_process_received_packet(packet, ret);
> ^^ (2) here it will be passed in Net stack
>
> 		if (ret >= 0 && eth_get_ops(current)->free_pkt)
> 			eth_get_ops(current)->free_pkt(current, packet, ret);
> ^^ at this point it should be safe to return buffer in DMA RX ring.
>
> 		if (ret <= 0)
> 			break;
>
> Can DMA overwrite packet after point (1) while packet is still processed (2)?
I don't think so, because as far as I know u-boot is not processing more 
than one packet at once, is it?
But yeah, I see your point and if it does process more than one packet 
at once this is not the proper way to do that.
I will use free_pkt in next version and lock the packet until it's 
processed.
>
>> +
>> +	/* set flow control buffer alloc */
>> +	writel_be(1, priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
>> +
>> +	/* enable dma */
>> +	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
>> +
>> +	/* set interrupt */
>> +	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_EN_REG(dma->id));
>> +
>> +	/* increment dma descriptor */
>> +	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->dma_ring_size;
>> +
>> +	return ret - 4;
>> +}
>> +
>
>
Regards,
Álvaro.

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 03/15] dma: add bcm6348-iudma support
  2018-02-22 20:48       ` Álvaro Fernández Rojas
@ 2018-02-23 16:57         ` Grygorii Strashko
  2018-03-03  9:06           ` Álvaro Fernández Rojas
  0 siblings, 1 reply; 106+ messages in thread
From: Grygorii Strashko @ 2018-02-23 16:57 UTC (permalink / raw)
  To: u-boot

Hi

thanks for your comments.

On 02/22/2018 02:48 PM, Álvaro Fernández Rojas wrote:
> El 22/02/2018 a las 20:50, Grygorii Strashko escribió:
>> On 02/21/2018 10:10 AM, Álvaro Fernández Rojas wrote:
>>> BCM6348 IUDMA controller is present on multiple BMIPS (BCM63xx) SoCs.
>>>
>>> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
>>> ---
>>>    v3: no changes
>>>    v2: Fix dma rx burst config and select DMA_CHANNELS.
>>>
>>>    drivers/dma/Kconfig         |   9 +
>>>    drivers/dma/Makefile        |   1 +
>>>    drivers/dma/bcm6348-iudma.c | 505 
>>> ++++++++++++++++++++++++++++++++++++++++++++
>>>    3 files changed, 515 insertions(+)
>>>    create mode 100644 drivers/dma/bcm6348-iudma.c
>>>
>> [...]
>>> +static int bcm6348_iudma_enable(struct dma *dma)
>>> +{
>>> +    struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
>>> +    struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
>>> +    struct bcm6348_dma_desc *dma_desc;
>>> +    uint8_t i;
>>> +
>>> +    /* init dma rings */
>>> +    dma_desc = ch_priv->dma_ring;
>>> +    for (i = 0; i < ch_priv->dma_ring_size; i++) {
>>> +        if (bcm6348_iudma_chan_is_rx(dma->id)) {
>>> +            dma_desc->status = DMAD_ST_OWN_MASK;
>>> +            dma_desc->length = PKTSIZE_ALIGN;
>>> +            dma_desc->address = virt_to_phys(net_rx_packets[i]);
>> You are filling RX queue/ring with buffers defined in Net core.
>> Does it mean that this DMA driver will not be usable for other 
>> purposes, as
>> Net can be compiled out?
> As far as I know, and depending on the specific SoC, BCM63xx IUDMA is 
> used for Ethernet, USB (device only) and xDSL.
> So yes, in u-boot it will be used for ethernet only.
> BTW, my first attempt didn't use net_rx_packets, but I saw that in 
> pic32_eth implementation and dropped the dma specific buffers. I will 
> add them again ;).

it is really net specific :)

>>
>> Wouldn't it be reasonable to have some sort of .receive_prepare() 
>> callback in
>> DMA dma_ops, so DMA user can control which buffers to push in RX DMA 
>> channel?
>> And it also can be used in eth_ops.free_pkt() callback (see below).
> Yes, probably, but maybe we can achieve that without adding another call.
>>

I'm looking at this patch set from our HW point of view. In my case,
DMA channel can be used with different IPs (not only networking), so
it would be really great if DMA user can pass RX buffers in DMA driver -
network driver can use net_rx_packets, other drivers might use own buffers.
So hard-codding RX buffers in DMA driver looks like not a good choice.

>>> +
>>> +    /* flush cache */
>>> +    flush_dcache_range((ulong)dma_desc,
>>> +        ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
>> Could you clarify pls, if you do return dma_desc to RX ring here or not?
> Yes.
>>
>> if yes, wouldn't it cause potential problem on Net RX path
>>         ret = eth_get_ops(current)->recv(current, flags, &packet);
>> ^^ (1) here buffer will be received from DMA ( and pushed back to RX 
>> ring ?? )
>>
>>         flags = 0;
>>         if (ret > 0)
>>             net_process_received_packet(packet, ret);
>> ^^ (2) here it will be passed in Net stack
>>
>>         if (ret >= 0 && eth_get_ops(current)->free_pkt)
>>             eth_get_ops(current)->free_pkt(current, packet, ret);
>> ^^ at this point it should be safe to return buffer in DMA RX ring.
>>
>>         if (ret <= 0)
>>             break;
>>
>> Can DMA overwrite packet after point (1) while packet is still 
>> processed (2)?
> I don't think so, because as far as I know u-boot is not processing more 
> than one packet at once, is it?

u-boot can't process more than one packet, but dma does. if buffer returned
to DMA and there are some traffic on the line - DMA can potentially refill 
all buffers in its RX ring while u-boot still processing one packet.


> But yeah, I see your point and if it does process more than one packet 
> at once this is not the proper way to do that.
> I will use free_pkt in next version and lock the packet until it's 
> processed.


-- 
regards,
-grygorii

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (16 preceding siblings ...)
  2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
@ 2018-03-03  8:59 ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
                     ` (14 more replies)
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
  18 siblings, 15 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

In order to add bcm6348-enet support, dma-uclass must be extended to support
dma channels and reworked to operate like the other dm uclass (clk, reset...).

This is a RFC, so please give you feedback on the things that I should
fix or rework.

v4: Fix issues reported by Grygorii Strashko and other fixes:
 - Remove usage of net_rx_packets as buffer from bcm6348-iudma.
 - Allocate dynamic rx buffer on bcm6348-iudma.
 - Copy received dma buffer to net_rx_packets in order to avoid possible
 dma overwrites.
 - Check dma errors and discard invalid packets.
 - Reset dma rx channel when sending a new packet to prevent flow control
 issues.
 - Fix packet casting on bcm6348_eth_recv/send.
v3: Introduce changes reported by Simon Glass:
 - Improve dma-uclass.h documentation.
 - Switch to live tree API.
v2: Introduce changes reported by Vignesh:
 - Respect current dma implementation.
 - Let dma_memcpy find a compatible dma device.
Other changes:
 - Fix bcm6348-iudma rx burst config.

Álvaro Fernández Rojas (15):
  dma: move dma_ops to dma-uclass.h
  dma: add channels support
  dma: add bcm6348-iudma support
  bmips: bcm6338: add bcm6348-iudma support
  bmips: bcm6348: add bcm6348-iudma support
  bmips: bcm6358: add bcm6348-iudma support
  phy: add support for internal phys
  net: add support for bcm6348-enet
  bmips: bcm6338: add support for bcm6348-enet
  bmips: enable f at st1704 enet support
  bmips: bcm6348: add support for bcm6348-enet
  bmips: enable ct-5361 enet support
  bmips: bcm6358: add support for bcm6348-enet
  bmips: enable hg556a enet support
  bmips: enable nb4-ser enet support

 arch/mips/dts/brcm,bcm6338.dtsi       |  29 ++
 arch/mips/dts/brcm,bcm6348.dtsi       |  42 +++
 arch/mips/dts/brcm,bcm6358.dtsi       |  46 +++
 arch/mips/dts/comtrend,ct-5361.dts    |  12 +
 arch/mips/dts/huawei,hg556a.dts       |  12 +
 arch/mips/dts/sagem,f at st1704.dts      |  12 +
 arch/mips/dts/sfr,nb4-ser.dts         |  24 ++
 configs/comtrend_ct5361_ram_defconfig |   8 +-
 configs/huawei_hg556a_ram_defconfig   |   8 +-
 configs/sagem_f at st1704_ram_defconfig  |   9 +-
 configs/sfr_nb4-ser_ram_defconfig     |   8 +-
 drivers/dma/Kconfig                   |  16 +
 drivers/dma/Makefile                  |   1 +
 drivers/dma/bcm6348-iudma.c           | 545 ++++++++++++++++++++++++++++++++++
 drivers/dma/dma-uclass.c              | 191 +++++++++++-
 drivers/net/Kconfig                   |  10 +
 drivers/net/Makefile                  |   1 +
 drivers/net/bcm6348-eth.c             | 530 +++++++++++++++++++++++++++++++++
 include/configs/bmips_common.h        |   5 +-
 include/dma-uclass.h                  | 117 ++++++++
 include/dma.h                         | 196 ++++++++++--
 include/dt-bindings/dma/bcm6338-dma.h |  15 +
 include/dt-bindings/dma/bcm6348-dma.h |  17 ++
 include/dt-bindings/dma/bcm6358-dma.h |  17 ++
 include/phy.h                         |   2 +
 25 files changed, 1837 insertions(+), 36 deletions(-)
 create mode 100644 drivers/dma/bcm6348-iudma.c
 create mode 100644 drivers/net/bcm6348-eth.c
 create mode 100644 include/dma-uclass.h
 create mode 100644 include/dt-bindings/dma/bcm6338-dma.h
 create mode 100644 include/dt-bindings/dma/bcm6348-dma.h
 create mode 100644 include/dt-bindings/dma/bcm6358-dma.h

-- 
2.11.0

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 01/15] dma: move dma_ops to dma-uclass.h
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-05 19:38     ` Grygorii Strashko
  2018-03-03  8:59   ` [U-Boot] [RFC v4 02/15] dma: add channels support Álvaro Fernández Rojas
                     ` (13 subsequent siblings)
  14 siblings, 1 reply; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Move dma_ops to a separate header file, following other uclass implementations.
While doing so, this patch also improves dma_ops documentation.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---
 v4: no changes
 v3: Introduce changes reported by Simon Glass:
  - Improve dma-uclass.h documentation.
  - Switch to live tree API.

 drivers/dma/dma-uclass.c |  3 ++-
 include/dma-uclass.h     | 39 +++++++++++++++++++++++++++++++++++++++
 include/dma.h            | 22 ----------------------
 3 files changed, 41 insertions(+), 23 deletions(-)
 create mode 100644 include/dma-uclass.h

diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
index 3d0ce22fbc..6fd4e1b35d 100644
--- a/drivers/dma/dma-uclass.c
+++ b/drivers/dma/dma-uclass.c
@@ -10,10 +10,11 @@
  */
 
 #include <common.h>
-#include <dma.h>
 #include <dm.h>
 #include <dm/uclass-internal.h>
 #include <dm/device-internal.h>
+#include <dma.h>
+#include <dma-uclass.h>
 #include <errno.h>
 
 DECLARE_GLOBAL_DATA_PTR;
diff --git a/include/dma-uclass.h b/include/dma-uclass.h
new file mode 100644
index 0000000000..3429f65ec4
--- /dev/null
+++ b/include/dma-uclass.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DMA_UCLASS_H
+#define _DMA_UCLASS_H
+
+/* See dma.h for background documentation. */
+
+#include <dma.h>
+
+/*
+ * struct dma_ops - Driver model DMA operations
+ *
+ * The uclass interface is implemented by all DMA devices which use
+ * driver model.
+ */
+struct dma_ops {
+	/**
+	 * transfer() - Issue a DMA transfer. The implementation must
+	 *   wait until the transfer is done.
+	 *
+	 * @dev: The DMA device
+	 * @direction: direction of data transfer (should be one from
+	 *   enum dma_direction)
+	 * @dst: The destination pointer.
+	 * @src: The source pointer.
+	 * @len: Length of the data to be copied (number of bytes).
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*transfer)(struct udevice *dev, int direction, void *dst,
+			void *src, size_t len);
+};
+
+#endif /* _DMA_UCLASS_H */
diff --git a/include/dma.h b/include/dma.h
index 71fa77f2ea..89320f10d9 100644
--- a/include/dma.h
+++ b/include/dma.h
@@ -28,28 +28,6 @@ enum dma_direction {
 #define DMA_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, should be
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 02/15] dma: add channels support
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
                     ` (12 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

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 <noltari@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---
 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 6fd4e1b35d..f4ba883b12 100644
--- a/drivers/dma/dma-uclass.c
+++ b/drivers/dma/dma-uclass.c
@@ -1,24 +1,200 @@
 /*
  * Direct Memory Access U-Class driver
  *
- * (C) Copyright 2015
- *     Texas Instruments Incorporated, <www.ti.com>
- *
- * Author: Mugunthan V N <mugunthanvnm@ti.com>
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
  *
  * SPDX-License-Identifier:     GPL-2.0+
  */
 
 #include <common.h>
 #include <dm.h>
-#include <dm/uclass-internal.h>
-#include <dm/device-internal.h>
+#include <dm/read.h>
 #include <dma.h>
 #include <dma-uclass.h>
+#include <dt-structs.h>
 #include <errno.h>
 
 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, &dma->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,
+					 &args);
+	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, &dev_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, &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);
+	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, 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 3429f65ec4..b334adb68b 100644
--- a/include/dma-uclass.h
+++ b/include/dma-uclass.h
@@ -13,6 +13,8 @@
 
 #include <dma.h>
 
+struct ofnode_phandle_args;
+
 /*
  * struct dma_ops - Driver model DMA operations
  *
@@ -20,6 +22,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 ofnode_phandle_args *args);
+	/**
+	 * request - Request a translated DMA.
+	 *
+	 * The DMA core calls this function as the second step in
+	 * implementing a client's dma_get_by_*() call, following a successful
+	 * xxx_xlate() call, or as the only step in implementing a client's
+	 * dma_request() call.
+	 *
+	 * @dma: The DMA struct to request; this has been filled in by
+	 *   a previoux xxx_xlate() function call, or by the caller of
+	 *   dma_request().
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*request)(struct dma *dma);
+	/**
+	 * free - Free a previously requested dma.
+	 *
+	 * This is the implementation of the client dma_free() API.
+	 *
+	 * @dma: The DMA to free.
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*free)(struct dma *dma);
+	/**
+	 * enable() - Enable a DMA Channel.
+	 *
+	 * @dma: The DMA Channel to manipulate.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*enable)(struct dma *dma);
+	/**
+	 * disable() - Disable a DMA Channel.
+	 *
+	 * @dma: The DMA Channel to manipulate.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*disable)(struct dma *dma);
+	/**
+	 * 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);
+#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, <www.ti.com>
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
  *
  * SPDX-License-Identifier:     GPL-2.0+
  */
@@ -8,6 +9,9 @@
 #ifndef _DMA_H_
 #define _DMA_H_
 
+#include <linux/errno.h>
+#include <linux/types.h>
+
 /*
  * 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 provider. A provider will
+ * often implement multiple separate DMAs, since the hardware it manages
+ * often has this capability. dma_uclass.h describes the interface which
+ * DMA providers must implement.
+ *
+ * DMA consumers/clients are the HW modules driven by the DMA channels. This
+ * header file describes the API used by drivers for those HW modules.
+ */
+
+struct udevice;
+
+/**
+ * struct dma - A handle to (allowing control of) a single DMA.
+ *
+ * Clients provide storage for DMA handles. The content of the structure is
+ * managed solely by the DMA API and DMA drivers. A DMA struct is
+ * initialized by "get"ing the DMA struct. The DMA struct is passed to all
+ * other DMA APIs to identify which DMA channel to operate upon.
+ *
+ * @dev: The device which implements the DMA channel.
+ * @id: The DMA channel ID within the provider.
+ *
+ * Currently, the DMA API assumes that a single integer ID is enough to
+ * identify and configure any DMA channel for any DMA provider. If this
+ * assumption becomes invalid in the future, the struct could be expanded to
+ * either (a) add more fields to allow DMA providers to store additional
+ * information, or (b) replace the id field with an opaque pointer, which the
+ * provider would dynamically allocated during its .of_xlate op, and process
+ * during is .request op. This may require the addition of an extra op to clean
+ * up the allocation.
+ */
+struct dma {
+	struct udevice *dev;
+	/*
+	 * Written by of_xlate. We assume a single id is enough for now. In the
+	 * future, we might add more fields here.
+	 */
+	unsigned long id;
+};
+
+# if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DMA)
+struct phandle_1_arg;
+int dma_get_by_index_platdata(struct udevice *dev, int index,
+			      struct phandle_1_arg *cells, struct dma *dma);
+
+/**
+ * dma_get_by_index - Get/request a DMA by integer index.
+ *
+ * This looks up and requests a DMA. The index is relative to the client
+ * device; each device is assumed to have n DMAs associated with it somehow,
+ * and this function finds and requests one of them. The mapping of client
+ * device DMA indices to provider DMAs may be via device-tree properties,
+ * board-provided mapping tables, or some other mechanism.
+ *
+ * @dev:	The client device.
+ * @index:	The index of the DMA to request, within the client's list of
+ *		DMA channels.
+ * @dma:	A pointer to a DMA struct to initialize.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_get_by_index(struct udevice *dev, int index, struct dma *dma);
+
+/**
+ * dma_get_by_name - Get/request a DMA by name.
+ *
+ * This looks up and requests a DMA. The name is relative to the client
+ * device; each device is assumed to have n DMAs associated with it somehow,
+ * and this function finds and requests one of them. The mapping of client
+ * device DMA names to provider DMAs may be via device-tree properties,
+ * board-provided mapping tables, or some other mechanism.
+ *
+ * @dev:	The client device.
+ * @name:	The name of the DMA to request, within the client's list of
+ *		DMA channels.
+ * @dma:	A pointer to a DMA struct to initialize.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma);
+# else
+static inline int dma_get_by_index(struct udevice *dev, int index,
+				   struct dma *dma)
+{
+	return -ENOSYS;
+}
+
+static inline int dma_get_by_name(struct udevice *dev, const char *name,
+			   struct dma *dma)
+{
+	return -ENOSYS;
+}
+# endif
+
+/**
+ * dma_request - Request a DMA by provider-specific ID.
+ *
+ * This requests a DMA using a provider-specific ID. Generally, this function
+ * should not be used, since dma_get_by_index/name() provide an interface that
+ * better separates clients from intimate knowledge of DMA providers.
+ * However, this function may be useful in core SoC-specific code.
+ *
+ * @dev: The DMA provider device.
+ * @dma: A pointer to a DMA struct to initialize. The caller must
+ *	 have already initialized any field in this struct which the
+ *	 DMA provider uses to identify the DMA channel.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_request(struct udevice *dev, struct dma *dma);
+
+/**
+ * dma_free - Free a previously requested DMA.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_free(struct dma *dma);
+
+/**
+ * dma_enable() - Enable (turn on) a DMA channel.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return zero on success, or -ve error code.
+ */
+int dma_enable(struct dma *dma);
+
+/**
+ * dma_disable() - Disable (turn off) a DMA channel.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return zero on success, or -ve error code.
+ */
+int dma_disable(struct dma *dma);
+
+/**
+ * dma_receive() - Receive a DMA transfer.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @dst: The destination pointer.
+ * @return zero on success, or -ve error code.
+ */
+int dma_receive(struct dma *dma, void **dst);
+
+/**
+ * dma_send() - Send a DMA transfer.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @src: The source pointer.
+ * @len: Length of the data to be sent (number of bytes).
+ * @return zero on success, or -ve error code.
+ */
+int dma_send(struct dma *dma, void *src, size_t len);
+#endif /* CONFIG_DMA_CHANNELS */
+
 /*
  * dma_get_device - get a DMA device which supports transfer
  * type of transfer_type
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 03/15] dma: add bcm6348-iudma support
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 02/15] dma: add channels support Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 04/15] bmips: bcm6338: " Álvaro Fernández Rojas
                     ` (11 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

BCM6348 IUDMA controller is present on multiple BMIPS (BCM63xx) SoCs.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: Fix issues reported by Grygorii Strashko and other fixes:
  - Remove usage of net_rx_packets as buffer.
  - Allocate dynamic rx buffer.
  - Check dma errors and discard invalid packets.
 v3: no changes
 v2: Fix dma rx burst config and select DMA_CHANNELS.

 drivers/dma/Kconfig         |   9 +
 drivers/dma/Makefile        |   1 +
 drivers/dma/bcm6348-iudma.c | 545 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 555 insertions(+)
 create mode 100644 drivers/dma/bcm6348-iudma.c

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 21b2c0dcaa..9afa158b51 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -19,6 +19,15 @@ config DMA_CHANNELS
 	  Enable channels support for DMA. Some DMA controllers have multiple
 	  channels which can either transfer data to/from different devices.
 
+config BCM6348_IUDMA
+	bool "BCM6348 IUDMA driver"
+	depends on ARCH_BMIPS
+	select DMA_CHANNELS
+	help
+	  Enable the BCM6348 IUDMA driver.
+	  This driver support data transfer from devices to
+	  memory and from memory to devices.
+
 config TI_EDMA3
 	bool "TI EDMA3 driver"
 	help
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 39b78b2a3d..b2b4147349 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_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_BCM6348_IUDMA) += bcm6348-iudma.o
 obj-$(CONFIG_FSL_DMA) += fsl_dma.o
 obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
 obj-$(CONFIG_TI_EDMA3) += ti-edma3.o
diff --git a/drivers/dma/bcm6348-iudma.c b/drivers/dma/bcm6348-iudma.c
new file mode 100644
index 0000000000..d88345e45c
--- /dev/null
+++ b/drivers/dma/bcm6348-iudma.c
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/dma/bcm63xx-iudma.c:
+ *	Copyright (C) 2015 Simon Arlott <simon@fire.lp0.eu>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
+ *	Copyright (C) 2000-2010 Broadcom Corporation
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/bcmdrivers/opensource/net/enet/impl4/bcmenet.c:
+ *	Copyright (C) 2010 Broadcom Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma-uclass.h>
+#include <memalign.h>
+#include <reset.h>
+#include <asm/io.h>
+
+#define DMA_RX_DESC	4
+#define DMA_TX_DESC	1
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ALIGN_END_ADDR(type, ptr, size)	\
+	((unsigned long)(ptr) + roundup((size) * sizeof(type), \
+	 ARCH_DMA_MINALIGN))
+
+/* DMA Channels */
+#define DMA_CHAN_FLOWC(x)		((x) >> 1)
+#define DMA_CHAN_FLOWC_MAX		8
+#define DMA_CHAN_MAX			16
+#define DMA_CHAN_SIZE			0x10
+#define DMA_CHAN_TOUT			500
+
+/* DMA Global Configuration register */
+#define DMA_CFG_REG			0x00
+#define DMA_CFG_ENABLE_SHIFT		0
+#define DMA_CFG_ENABLE_MASK		(1 << DMA_CFG_ENABLE_SHIFT)
+#define DMA_CFG_FLOWC_ENABLE(x)		BIT(DMA_CHAN_FLOWC(x) + 1)
+#define DMA_CFG_NCHANS_SHIFT		24
+#define DMA_CFG_NCHANS_MASK		(0xf << DMA_CFG_NCHANS_SHIFT)
+
+/* DMA Global Flow Control Threshold registers */
+#define DMA_FLOWC_THR_LO_REG(x)		(0x04 + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_THR_LO_SHIFT		0
+#define DMA_FLOWC_THR_LO_MASK		(5 << DMA_FLOWC_THR_LO_SHIFT)
+
+#define DMA_FLOWC_THR_HI_REG(x)		(0x08 + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_THR_HI_SHIFT		0
+#define DMA_FLOWC_THR_HI_MASK		(10 << DMA_FLOWC_THR_HI_SHIFT)
+
+/* DMA Global Flow Control Buffer Allocation registers */
+#define DMA_FLOWC_ALLOC_REG(x)		(0x0c + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_ALLOC_FORCE_SHIFT	31
+#define DMA_FLOWC_ALLOC_FORCE_MASK	(1 << DMA_FLOWC_ALLOC_FORCE_SHIFT)
+
+/* DMA Global Reset register */
+#define DMA_RST_REG			0x34
+#define DMA_RST_CHAN_SHIFT		0
+#define DMA_RST_CHAN_MASK(x)		(1 << x)
+
+/* DMA Channel Configuration register */
+#define DMAC_CFG_REG(x)			(DMA_CHAN_SIZE * (x) + 0x00)
+#define DMAC_CFG_ENABLE_SHIFT		0
+#define DMAC_CFG_ENABLE_MASK		(1 << DMAC_CFG_ENABLE_SHIFT)
+#define DMAC_CFG_PKT_HALT_SHIFT		1
+#define DMAC_CFG_PKT_HALT_MASK		(1 << DMAC_CFG_PKT_HALT_SHIFT)
+#define DMAC_CFG_BRST_HALT_SHIFT	2
+#define DMAC_CFG_BRST_HALT_MASK		(1 << DMAC_CFG_BRST_HALT_SHIFT)
+
+/* DMA Channel Interrupts registers */
+#define DMAC_IR_ST_REG(x)		(DMA_CHAN_SIZE * (x) + 0x04)
+#define DMAC_IR_EN_REG(x)		(DMA_CHAN_SIZE * (x) + 0x08)
+
+#define DMAC_IR_DONE_SHIFT		2
+#define DMAC_IR_DONE_MASK		(1 << DMAC_IR_DONE_SHIFT)
+
+/* DMA Channel Max Burst Length register */
+#define DMAC_BURST_REG(x)		(DMA_CHAN_SIZE * (x) + 0x0c)
+#define DMAC_BURST_MAX_SHIFT		0
+#define DMAC_BURST_MAX_MASK		(16 << DMAC_BURST_MAX_SHIFT)
+
+/* DMA SRAM Descriptor Ring Start register */
+#define DMAS_RSTART_REG(x)		(DMA_CHAN_SIZE * (x) + 0x00)
+
+/* DMA SRAM State/Bytes done/ring offset register */
+#define DMAS_STATE_DATA_REG(x)		(DMA_CHAN_SIZE * (x) + 0x04)
+
+/* DMA SRAM Buffer Descriptor status and length register */
+#define DMAS_DESC_LEN_STATUS_REG(x)	(DMA_CHAN_SIZE * (x) + 0x08)
+
+/* DMA SRAM Buffer Descriptor status and length register */
+#define DMAS_DESC_BASE_BUFPTR_REG(x)	(DMA_CHAN_SIZE * (x) + 0x0c)
+
+struct bcm6348_dma_desc {
+	uint16_t length;
+
+	uint16_t status;
+#define DMAD_ST_OV_ERR_SHIFT	0
+#define DMAD_ST_OV_ERR_MASK	(1 << DMAD_ST_OV_ERR_SHIFT)
+#define DMAD_ST_CRC_ERR_SHIFT	1
+#define DMAD_ST_CRC_ERR_MASK	(1 << DMAD_ST_CRC_ERR_SHIFT)
+#define DMAD_ST_RX_ERR_SHIFT	2
+#define DMAD_ST_RX_ERR_MASK	(1 << DMAD_ST_RX_ERR_SHIFT)
+#define DMAD_ST_OS_ERR_SHIFT	4
+#define DMAD_ST_OS_ERR_MASK	(1 << DMAD_ST_OS_ERR_SHIFT)
+#define DMAD_ST_CRC_SHIFT	8
+#define DMAD_ST_CRC_MASK	(1 << DMAD_ST_CRC_SHIFT)
+#define DMAD_ST_UN_ERR_SHIFT	9
+#define DMAD_ST_UN_ERR_MASK	(1 << DMAD_ST_UN_ERR_SHIFT)
+#define DMAD_ST_WRAP_SHIFT	12
+#define DMAD_ST_WRAP_MASK	(1 << DMAD_ST_WRAP_SHIFT)
+#define DMAD_ST_SOP_SHIFT	13
+#define DMAD_ST_SOP_MASK	(1 << DMAD_ST_SOP_SHIFT)
+#define DMAD_ST_EOP_SHIFT	14
+#define DMAD_ST_EOP_MASK	(1 << DMAD_ST_EOP_SHIFT)
+#define DMAD_ST_OWN_SHIFT	15
+#define DMAD_ST_OWN_MASK	(1 << DMAD_ST_OWN_SHIFT)
+
+#define DMAD_ST_ERR_MASK	(DMAD_ST_OV_ERR_MASK | \
+				 DMAD_ST_CRC_ERR_MASK | \
+				 DMAD_ST_RX_ERR_MASK | \
+				 DMAD_ST_OS_ERR_MASK | \
+				 DMAD_ST_UN_ERR_MASK)
+
+	uint32_t address;
+} __attribute__((aligned(1)));
+
+struct bcm6348_chan_priv {
+	void __iomem *dma_buff;
+	void __iomem *dma_ring;
+	uint8_t dma_ring_size;
+	uint8_t desc_id;
+};
+
+struct bcm6348_iudma_priv {
+	void __iomem *base;
+	void __iomem *chan;
+	void __iomem *sram;
+	struct bcm6348_chan_priv **ch_priv;
+	uint8_t n_channels;
+};
+
+static inline bool bcm6348_iudma_chan_is_rx(uint8_t ch)
+{
+	return !(ch & 1);
+}
+
+static void bcm6348_iudma_chan_stop(struct bcm6348_iudma_priv *priv,
+				    uint8_t ch)
+{
+	unsigned int timeout = DMA_CHAN_TOUT;
+
+	/* disable dma channel interrupts */
+	writel_be(0, priv->chan + DMAC_IR_EN_REG(ch));
+
+	do {
+		uint32_t cfg, halt;
+
+		if (timeout > DMA_CHAN_TOUT / 2)
+			halt = DMAC_CFG_PKT_HALT_MASK;
+		else
+			halt = DMAC_CFG_BRST_HALT_MASK;
+
+		/* try to stop dma channel */
+		writel_be(halt, priv->chan + DMAC_CFG_REG(ch));
+		mb();
+
+		/* check if channel was stopped */
+		cfg = readl_be(priv->chan + DMAC_CFG_REG(ch));
+		if (!(cfg & DMAC_CFG_ENABLE_MASK))
+			break;
+
+		udelay(1);
+	} while (--timeout);
+
+	if (!timeout)
+		pr_err("unable to stop channel %u\n", ch);
+
+	/* reset dma channel */
+	setbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
+	mb();
+	clrbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
+}
+
+static int bcm6348_iudma_disable(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+
+	bcm6348_iudma_chan_stop(priv, dma->id);
+
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		writel_be(DMA_FLOWC_ALLOC_FORCE_MASK,
+			  DMA_FLOWC_ALLOC_REG(dma->id));
+
+	return 0;
+}
+
+static int bcm6348_iudma_enable(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	void __iomem *dma_buff = ch_priv->dma_buff;
+	uint8_t i;
+
+	/* init dma rings */
+	dma_desc = ch_priv->dma_ring;
+	for (i = 0; i < ch_priv->dma_ring_size; i++) {
+		if (bcm6348_iudma_chan_is_rx(dma->id)) {
+			dma_desc->status = DMAD_ST_OWN_MASK;
+			dma_desc->length = PKTSIZE_ALIGN;
+			dma_desc->address = virt_to_phys(dma_buff);
+			dma_buff += PKTSIZE_ALIGN;
+		} else {
+			dma_desc->status = 0;
+			dma_desc->length = 0;
+			dma_desc->address = 0;
+		}
+
+		if (i == ch_priv->dma_ring_size - 1)
+			dma_desc->status |= DMAD_ST_WRAP_MASK;
+
+		if (bcm6348_iudma_chan_is_rx(dma->id))
+			writel_be(1,
+				  priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
+
+		dma_desc++;
+	}
+
+	/* init to first descriptor */
+	ch_priv->desc_id = 0;
+
+	/* force cache writeback */
+	flush_dcache_range((ulong)ch_priv->dma_ring,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, ch_priv->dma_ring,
+			       ch_priv->dma_ring_size));
+
+	/* clear sram */
+	writel_be(0, priv->sram + DMAS_STATE_DATA_REG(dma->id));
+	writel_be(0, priv->sram + DMAS_DESC_LEN_STATUS_REG(dma->id));
+	writel_be(0, priv->sram + DMAS_DESC_BASE_BUFPTR_REG(dma->id));
+
+	/* set dma ring start */
+	writel_be(virt_to_phys(ch_priv->dma_ring),
+		  priv->sram + DMAS_RSTART_REG(dma->id));
+
+	/* set flow control */
+	if (bcm6348_iudma_chan_is_rx(dma->id)) {
+		u32 val;
+
+		setbits_be32(priv->base + DMA_CFG_REG,
+			     DMA_CFG_FLOWC_ENABLE(dma->id));
+
+		val = ch_priv->dma_ring_size / 3;
+		writel_be(val, priv->base + DMA_FLOWC_THR_LO_REG(dma->id));
+
+		val = (ch_priv->dma_ring_size * 2) / 3;
+		writel_be(val, priv->base + DMA_FLOWC_THR_HI_REG(dma->id));
+	}
+
+	/* set dma max burst */
+	writel_be(ch_priv->dma_ring_size,
+		  priv->chan + DMAC_BURST_REG(dma->id));
+
+	/* clear interrupts */
+	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_ST_REG(dma->id));
+	writel_be(0, priv->chan + DMAC_IR_EN_REG(dma->id));
+
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	return 0;
+}
+
+static int bcm6348_iudma_request(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv;
+
+	/* check if channel is valid */
+	if (dma->id >= priv->n_channels)
+		return -ENODEV;
+
+	/* alloc channel private data */
+	priv->ch_priv[dma->id] = calloc(1, sizeof(struct bcm6348_chan_priv));
+	if (!priv->ch_priv[dma->id])
+		return -ENOMEM;
+	ch_priv = priv->ch_priv[dma->id];
+
+	/* alloc dma ring */
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		ch_priv->dma_ring_size = DMA_RX_DESC;
+	else
+		ch_priv->dma_ring_size = DMA_TX_DESC;
+
+	ch_priv->dma_ring =
+		malloc_cache_aligned(sizeof(struct bcm6348_dma_desc) *
+				     ch_priv->dma_ring_size);
+	if (!ch_priv->dma_ring)
+		return -ENOMEM;
+
+	if (bcm6348_iudma_chan_is_rx(dma->id)) {
+		ch_priv->dma_buff =
+			malloc_cache_aligned(PKTSIZE_ALIGN *
+					     ch_priv->dma_ring_size);
+		if (!ch_priv->dma_buff)
+			return -ENOMEM;
+	} else {
+		ch_priv->dma_buff = NULL;
+	}
+
+	return 0;
+}
+
+static int bcm6348_iudma_receive(struct dma *dma, void **dst)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	void __iomem *dma_buff;
+	int ret;
+
+	/* get dma ring descriptor address */
+	dma_desc = ch_priv->dma_ring;
+	dma_desc += ch_priv->desc_id;
+
+	/* invalidate cache data */
+	invalidate_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* check dma own */
+	if (dma_desc->status & DMAD_ST_OWN_MASK)
+		return -EAGAIN;
+
+	/* check pkt */
+	if (!(dma_desc->status & DMAD_ST_EOP_MASK) ||
+	    !(dma_desc->status & DMAD_ST_SOP_MASK) ||
+	    (dma_desc->status & DMAD_ST_ERR_MASK)) {
+		pr_err("invalid pkt received (ch=%ld)\n", dma->id);
+		ret = -EAGAIN;
+	} else {
+		uint16_t length;
+
+		/* get dma buff descriptor address */
+		dma_buff = phys_to_virt(dma_desc->address);
+
+		/* invalidate cache data */
+		invalidate_dcache_range((ulong)dma_buff,
+					(ulong)(dma_buff + PKTSIZE_ALIGN));
+
+		/* remove crc */
+		length = dma_desc->length - 4;
+
+		/* copy data */
+		memcpy(*dst, dma_buff, length);
+
+		ret = length;
+	}
+
+	/* reinit dma descriptor */
+	dma_desc->length = PKTSIZE_ALIGN;
+	dma_desc->status = (dma_desc->status & DMAD_ST_WRAP_MASK) |
+			   DMAD_ST_OWN_MASK;
+
+	/* flush cache */
+	flush_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* set flow control buffer alloc */
+	writel_be(1, priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
+
+	/* enable dma */
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	/* set interrupt */
+	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_EN_REG(dma->id));
+
+	/* increment dma descriptor */
+	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->dma_ring_size;
+
+	return ret;
+}
+
+static int bcm6348_iudma_send(struct dma *dma, void *src, size_t len)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	uint16_t val;
+
+	/* get dma ring descriptor address */
+	dma_desc = ch_priv->dma_ring;
+	dma_desc += ch_priv->desc_id;
+
+	dma_desc->address = virt_to_phys(src);
+
+	/* config dma descriptor */
+	val = (DMAD_ST_OWN_MASK |
+	       DMAD_ST_EOP_MASK |
+	       DMAD_ST_CRC_MASK |
+	       DMAD_ST_SOP_MASK);
+	if (ch_priv->desc_id == ch_priv->dma_ring_size - 1)
+		val |= DMAD_ST_WRAP_MASK;
+
+	dma_desc->length = len;
+	dma_desc->status = val;
+
+	/* flush cache */
+	flush_dcache_range((ulong)src, (ulong)src + PKTSIZE_ALIGN);
+
+	/* flush cache */
+	flush_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* enable dma */
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	/* set interrupt */
+	writel_be(DMAC_IR_DONE_MASK, priv->chan + DMAC_IR_EN_REG(dma->id));
+
+	/* poll dma status */
+	do {
+		/* invalidate cache */
+		invalidate_dcache_range((ulong)dma_desc,
+			ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+		if (!(dma_desc->status & DMAD_ST_OWN_MASK))
+			break;
+	} while(1);
+
+	/* increment dma descriptor */
+	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->dma_ring_size;
+
+	return 0;
+}
+
+static const struct dma_ops bcm6348_iudma_ops = {
+	.disable = bcm6348_iudma_disable,
+	.enable = bcm6348_iudma_enable,
+	.request = bcm6348_iudma_request,
+	.receive = bcm6348_iudma_receive,
+	.send = bcm6348_iudma_send,
+};
+
+static const struct udevice_id bcm6348_iudma_ids[] = {
+	{ .compatible = "brcm,bcm6348-iudma", },
+	{ /* sentinel */ }
+};
+
+static int bcm6348_iudma_probe(struct udevice *dev)
+{
+	struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+	uint8_t ch;
+	int i;
+
+	uc_priv->supported = DMA_SUPPORTS_DEV_TO_MEM |
+			     DMA_SUPPORTS_MEM_TO_DEV;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+		if (clk_enable(&clk))
+			pr_err("failed to enable clock %d\n", i);
+		clk_free(&clk);
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+		if (reset_deassert(&reset))
+			pr_err("failed to deassert reset %d\n", i);
+		reset_free(&reset);
+	}
+
+	/* dma global base address */
+	addr = devfdt_get_addr_name(dev, "dma");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->base = ioremap(addr, 0);
+
+	/* dma channels base address */
+	addr = devfdt_get_addr_name(dev, "dma-channels");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->chan = ioremap(addr, 0);
+
+	/* dma sram base address */
+	addr = devfdt_get_addr_name(dev, "dma-sram");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->sram = ioremap(addr, 0);
+
+	/* disable dma controller */
+	clrbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
+
+	/* get number of channels */
+	priv->n_channels = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+					   "dma-channels", 8);
+	if (priv->n_channels > DMA_CHAN_MAX)
+		return -EINVAL;
+
+	/* alloc channel private data pointers */
+	priv->ch_priv = calloc(priv->n_channels,
+			       sizeof(struct bcm6348_chan_priv*));
+	if (!priv->ch_priv)
+		return -ENOMEM;
+
+	/* stop dma channels */
+	for (ch = 0; ch < priv->n_channels; ch++)
+		bcm6348_iudma_chan_stop(priv, ch);
+
+	/* enable dma controller */
+	setbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_iudma) = {
+	.name = "bcm6348_iudma",
+	.id = UCLASS_DMA,
+	.of_match = bcm6348_iudma_ids,
+	.ops = &bcm6348_iudma_ops,
+	.priv_auto_alloc_size = sizeof(struct bcm6348_iudma_priv),
+	.probe = bcm6348_iudma_probe,
+};
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 04/15] bmips: bcm6338: add bcm6348-iudma support
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (2 preceding siblings ...)
  2018-03-03  8:59   ` [U-Boot] [RFC v4 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 05/15] bmips: bcm6348: " Álvaro Fernández Rojas
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6338.dtsi       | 14 ++++++++++++++
 include/dt-bindings/dma/bcm6338-dma.h | 15 +++++++++++++++
 2 files changed, 29 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6338-dma.h

diff --git a/arch/mips/dts/brcm,bcm6338.dtsi b/arch/mips/dts/brcm,bcm6338.dtsi
index 0cab44cb8d..4125f71d9f 100644
--- a/arch/mips/dts/brcm,bcm6338.dtsi
+++ b/arch/mips/dts/brcm,bcm6338.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6338-clock.h>
+#include <dt-bindings/dma/bcm6338-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6338-reset.h>
 #include "skeleton.dtsi"
@@ -131,5 +132,18 @@
 			reg = <0xfffe3100 0x38>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller at fffe2400 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe2400 0x1c>,
+			      <0xfffe2500 0x60>,
+			      <0xfffe2600 0x60>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <6>;
+			resets = <&periph_rst BCM6338_RST_DMAMEM>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6338-dma.h b/include/dt-bindings/dma/bcm6338-dma.h
new file mode 100644
index 0000000000..5dd66239b4
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6338-dma.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6338_H
+#define __DT_BINDINGS_DMA_BCM6338_H
+
+#define BCM6338_DMA_ENET_RX	0
+#define BCM6338_DMA_ENET_TX	1
+
+#endif /* __DT_BINDINGS_DMA_BCM6338_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 05/15] bmips: bcm6348: add bcm6348-iudma support
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (3 preceding siblings ...)
  2018-03-03  8:59   ` [U-Boot] [RFC v4 04/15] bmips: bcm6338: " Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 06/15] bmips: bcm6358: " Álvaro Fernández Rojas
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6348.dtsi       | 16 ++++++++++++++++
 include/dt-bindings/dma/bcm6348-dma.h | 17 +++++++++++++++++
 2 files changed, 33 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6348-dma.h

diff --git a/arch/mips/dts/brcm,bcm6348.dtsi b/arch/mips/dts/brcm,bcm6348.dtsi
index 92fb91afc1..d774c59665 100644
--- a/arch/mips/dts/brcm,bcm6348.dtsi
+++ b/arch/mips/dts/brcm,bcm6348.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6348-clock.h>
+#include <dt-bindings/dma/bcm6348-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6348-reset.h>
 #include "skeleton.dtsi"
@@ -160,5 +161,20 @@
 			reg = <0xfffe2300 0x38>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller at fffe7000 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe7000 0x1c>,
+			      <0xfffe7100 0x40>,
+			      <0xfffe7200 0x40>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <4>;
+			clocks = <&periph_clk BCM6348_CLK_ENET>;
+			resets = <&periph_rst BCM6348_RST_ENET>,
+				 <&periph_rst BCM6348_RST_DMAMEM>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6348-dma.h b/include/dt-bindings/dma/bcm6348-dma.h
new file mode 100644
index 0000000000..a1d3a6456d
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6348-dma.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6348_H
+#define __DT_BINDINGS_DMA_BCM6348_H
+
+#define BCM6348_DMA_ENET0_RX	0
+#define BCM6348_DMA_ENET0_TX	1
+#define BCM6348_DMA_ENET1_RX	2
+#define BCM6348_DMA_ENET1_TX	3
+
+#endif /* __DT_BINDINGS_DMA_BCM6348_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 06/15] bmips: bcm6358: add bcm6348-iudma support
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (4 preceding siblings ...)
  2018-03-03  8:59   ` [U-Boot] [RFC v4 05/15] bmips: bcm6348: " Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 07/15] phy: add support for internal phys Álvaro Fernández Rojas
                     ` (8 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6358.dtsi       | 18 ++++++++++++++++++
 include/dt-bindings/dma/bcm6358-dma.h | 17 +++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6358-dma.h

diff --git a/arch/mips/dts/brcm,bcm6358.dtsi b/arch/mips/dts/brcm,bcm6358.dtsi
index b63b53baee..1468e4f63a 100644
--- a/arch/mips/dts/brcm,bcm6358.dtsi
+++ b/arch/mips/dts/brcm,bcm6358.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6358-clock.h>
+#include <dt-bindings/dma/bcm6358-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6358-reset.h>
 #include "skeleton.dtsi"
@@ -191,5 +192,22 @@
 
 			status = "disabled";
 		};
+
+		iudma: dma-controller at fffe5000 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe5000 0x24>,
+			      <0xfffe5100 0x80>,
+			      <0xfffe5200 0x80>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <8>;
+			clocks = <&periph_clk BCM6358_CLK_EMUSB>,
+				 <&periph_clk BCM6358_CLK_USBSU>,
+				 <&periph_clk BCM6358_CLK_EPHY>;
+			resets = <&periph_rst BCM6358_RST_ENET>,
+				 <&periph_rst BCM6358_RST_EPHY>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6358-dma.h b/include/dt-bindings/dma/bcm6358-dma.h
new file mode 100644
index 0000000000..3b1fcf8540
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6358-dma.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6358_H
+#define __DT_BINDINGS_DMA_BCM6358_H
+
+#define BCM6358_DMA_ENET0_RX	0
+#define BCM6358_DMA_ENET0_TX	1
+#define BCM6358_DMA_ENET1_RX	2
+#define BCM6358_DMA_ENET1_TX	3
+
+#endif /* __DT_BINDINGS_DMA_BCM6358_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 07/15] phy: add support for internal phys
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (5 preceding siblings ...)
  2018-03-03  8:59   ` [U-Boot] [RFC v4 06/15] bmips: bcm6358: " Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
                     ` (7 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: no changes
 v3: no changes
 v2: no changes

 include/phy.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/phy.h b/include/phy.h
index 0543ec10c2..8f3e53db01 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -50,6 +50,7 @@
 
 
 typedef enum {
+	PHY_INTERFACE_MODE_INTERNAL,
 	PHY_INTERFACE_MODE_MII,
 	PHY_INTERFACE_MODE_GMII,
 	PHY_INTERFACE_MODE_SGMII,
@@ -72,6 +73,7 @@ typedef enum {
 } phy_interface_t;
 
 static const char *phy_interface_strings[] = {
+	[PHY_INTERFACE_MODE_INTERNAL]		= "internal",
 	[PHY_INTERFACE_MODE_MII]		= "mii",
 	[PHY_INTERFACE_MODE_GMII]		= "gmii",
 	[PHY_INTERFACE_MODE_SGMII]		= "sgmii",
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 08/15] net: add support for bcm6348-enet
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (6 preceding siblings ...)
  2018-03-03  8:59   ` [U-Boot] [RFC v4 07/15] phy: add support for internal phys Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 09/15] bmips: bcm6338: " Álvaro Fernández Rojas
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: Fix issues reported by Grygorii Strashko and other fixes:
  - Copy received dma buffer to net_rx_packets in order to avoid possible
  dma overwrites.
  - Reset dma rx channel when sending a new packet to prevent flow control
  issues.
  - Fix packet casting on bcm6348_eth_recv/send.
 v3: no changes
 v2: select DMA_CHANNELS.

 drivers/net/Kconfig            |  10 +
 drivers/net/Makefile           |   1 +
 drivers/net/bcm6348-eth.c      | 530 +++++++++++++++++++++++++++++++++++++++++
 include/configs/bmips_common.h |   5 +-
 4 files changed, 545 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/bcm6348-eth.c

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index de1947ccc1..e532332d78 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -71,6 +71,16 @@ config BCM_SF2_ETH_GMAC
 	  by the BCM_SF2_ETH driver.
 	  Say Y to any bcmcygnus based platforms.
 
+config BCM6348_ETH
+	bool "BCM6348 EMAC support"
+	depends on DM_ETH && ARCH_BMIPS
+	select DMA
+	select DMA_CHANNELS
+	select MII
+	select PHYLIB
+	help
+	  This driver supports the BCM6348 Ethernet MAC.
+
 config DWC_ETH_QOS
 	bool "Synopsys DWC Ethernet QOS device support"
 	depends on DM_ETH
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index ac5443c752..282adbc775 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
 obj-$(CONFIG_AG7XXX) += ag7xxx.o
 obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
+obj-$(CONFIG_BCM6348_ETH) += bcm6348-eth.o
 obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
 obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
 obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
diff --git a/drivers/net/bcm6348-eth.c b/drivers/net/bcm6348-eth.c
new file mode 100644
index 0000000000..4f729373ee
--- /dev/null
+++ b/drivers/net/bcm6348-eth.c
@@ -0,0 +1,530 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma.h>
+#include <miiphy.h>
+#include <net.h>
+#include <phy.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+
+#define ETH_ZLEN			60
+
+#define ETH_TX_WATERMARK		32
+#define ETH_MAX_MTU_SIZE		1518
+
+#define ETH_TIMEOUT			100
+
+/* ETH Receiver Configuration register */
+#define ETH_RXCFG_REG			0x00
+#define ETH_RXCFG_ENFLOW_SHIFT		5
+#define ETH_RXCFG_ENFLOW_MASK		(1 << ETH_RXCFG_ENFLOW_SHIFT)
+
+/* ETH Receive Maximum Length register */
+#define ETH_RXMAXLEN_REG		0x04
+#define ETH_RXMAXLEN_SHIFT		0
+#define ETH_RXMAXLEN_MASK		(0x7ff << ETH_RXMAXLEN_SHIFT)
+
+/* ETH Transmit Maximum Length register */
+#define ETH_TXMAXLEN_REG		0x08
+#define ETH_TXMAXLEN_SHIFT		0
+#define ETH_TXMAXLEN_MASK		(0x7ff << ETH_TXMAXLEN_SHIFT)
+
+/* MII Status/Control register */
+#define MII_SC_REG			0x10
+#define MII_SC_MDCFREQDIV_SHIFT		0
+#define MII_SC_MDCFREQDIV_MASK		(0x7f << MII_SC_MDCFREQDIV_SHIFT)
+#define MII_SC_PREAMBLE_EN_SHIFT	7
+#define MII_SC_PREAMBLE_EN_MASK		(1 << MII_SC_PREAMBLE_EN_SHIFT)
+
+/* MII Data register */
+#define MII_DAT_REG			0x14
+#define MII_DAT_DATA_SHIFT		0
+#define MII_DAT_DATA_MASK		(0xffff << MII_DAT_DATA_SHIFT)
+#define MII_DAT_TA_SHIFT		16
+#define MII_DAT_TA_MASK			(0x3 << MII_DAT_TA_SHIFT)
+#define MII_DAT_REG_SHIFT		18
+#define MII_DAT_REG_MASK		(0x1f << MII_DAT_REG_SHIFT)
+#define MII_DAT_PHY_SHIFT		23
+#define MII_DAT_PHY_MASK		(0x1f << MII_DAT_PHY_SHIFT)
+#define MII_DAT_OP_SHIFT		28
+#define MII_DAT_OP_WRITE		(0x5 << MII_DAT_OP_SHIFT)
+#define MII_DAT_OP_READ			(0x6 << MII_DAT_OP_SHIFT)
+
+/* ETH Interrupts Mask register */
+#define ETH_IRMASK_REG			0x18
+
+/* ETH Interrupts register */
+#define ETH_IR_REG			0x1c
+#define ETH_IR_MII_SHIFT		0
+#define ETH_IR_MII_MASK			(1 << ETH_IR_MII_SHIFT)
+
+/* ETH Control register */
+#define ETH_CTL_REG			0x2c
+#define ETH_CTL_ENABLE_SHIFT		0
+#define ETH_CTL_ENABLE_MASK		(1 << ETH_CTL_ENABLE_SHIFT)
+#define ETH_CTL_DISABLE_SHIFT		1
+#define ETH_CTL_DISABLE_MASK		(1 << ETH_CTL_DISABLE_SHIFT)
+#define ETH_CTL_RESET_SHIFT		2
+#define ETH_CTL_RESET_MASK		(1 << ETH_CTL_RESET_SHIFT)
+#define ETH_CTL_EPHY_SHIFT		3
+#define ETH_CTL_EPHY_MASK		(1 << ETH_CTL_EPHY_SHIFT)
+
+/* ETH Transmit Control register */
+#define ETH_TXCTL_REG			0x30
+#define ETH_TXCTL_FD_SHIFT		0
+#define ETH_TXCTL_FD_MASK		(1 << ETH_TXCTL_FD_SHIFT)
+
+/* ETH Transmit Watermask register */
+#define ETH_TXWMARK_REG			0x34
+#define ETH_TXWMARK_WM_SHIFT		0
+#define ETH_TXWMARK_WM_MASK		(0x3f << ETH_TXWMARK_WM_SHIFT)
+
+/* MIB Control register */
+#define MIB_CTL_REG			0x38
+#define MIB_CTL_RDCLEAR_SHIFT		0
+#define MIB_CTL_RDCLEAR_MASK		(1 << MIB_CTL_RDCLEAR_SHIFT)
+
+/* ETH Perfect Match registers */
+#define ETH_PM_CNT			4
+#define ETH_PML_REG(x)			(0x58 + (x) * 0x8)
+#define ETH_PMH_REG(x)			(0x5c + (x) * 0x8)
+#define ETH_PMH_VALID_SHIFT		16
+#define ETH_PMH_VALID_MASK		(1 << ETH_PMH_VALID_SHIFT)
+
+/* MIB Counters registers */
+#define MIB_REG_CNT			55
+#define MIB_REG(x)			(0x200 + (x) * 4)
+
+/* ETH data */
+struct bcm6348_eth_priv {
+	void __iomem *base;
+	uint8_t rx_desc;
+	/* DMA */
+	struct dma rx_dma;
+	struct dma tx_dma;
+	/* PHY */
+	int phy_id;
+	struct phy_device *phy_dev;
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void bcm6348_eth_mac_disable(struct bcm6348_eth_priv *priv)
+{
+	/* disable emac */
+	clrsetbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK,
+			ETH_CTL_DISABLE_MASK);
+
+	/* wait until emac is disabled */
+	if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
+			      ETH_CTL_DISABLE_MASK, false,
+			      ETH_TIMEOUT, false))
+		pr_err("error disabling emac\n");
+}
+
+static void bcm6348_eth_mac_enable(struct bcm6348_eth_priv *priv)
+{
+	setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK);
+}
+
+static void bcm6348_eth_mac_reset(struct bcm6348_eth_priv *priv)
+{
+	/* reset emac */
+	writel_be(ETH_CTL_RESET_MASK, priv->base + ETH_CTL_REG);
+	wmb();
+
+	/* wait until emac is reset */
+	if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
+			      ETH_CTL_RESET_MASK, false,
+			      ETH_TIMEOUT, false))
+		pr_err("error resetting emac\n");
+}
+
+static int bcm6348_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	*packetp = net_rx_packets[priv->rx_desc];
+	ret = dma_receive(&priv->rx_dma, (void **)packetp);
+	if (ret > 0)
+		priv->rx_desc = (priv->rx_desc + 1) % PKTBUFSRX;
+
+	return ret;
+}
+
+static int bcm6348_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* reset dma rx channel */
+	dma_disable(&priv->rx_dma);
+	dma_enable(&priv->rx_dma);
+
+	length = max(length, ETH_ZLEN);
+
+	return dma_send(&priv->tx_dma, (void *)packet, length);
+}
+
+static int bcm6348_eth_adjust_link(struct udevice *dev,
+				   struct phy_device *phydev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* mac duplex parameters */
+	if (phydev->duplex)
+		setbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
+	else
+		clrbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
+
+	/* rx flow control (pause frame handling) */
+	if (phydev->pause)
+		setbits_be32(priv->base + ETH_RXCFG_REG,
+			     ETH_RXCFG_ENFLOW_MASK);
+	else
+		clrbits_be32(priv->base + ETH_RXCFG_REG,
+			     ETH_RXCFG_ENFLOW_MASK);
+
+	return 0;
+}
+
+static int bcm6348_eth_start(struct udevice *dev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	int ret, i;
+
+	priv->rx_desc = 0;
+
+	/* enable dma rx channel */
+	dma_enable(&priv->rx_dma);
+
+	/* enable dma tx channel */
+	dma_enable(&priv->tx_dma);
+
+	ret = phy_startup(priv->phy_dev);
+	if (ret) {
+		pr_err("could not initialize phy\n");
+		return ret;
+	}
+
+	if (!priv->phy_dev->link) {
+		pr_err("no phy link\n");
+		return -EIO;
+	}
+
+	bcm6348_eth_adjust_link(dev, priv->phy_dev);
+
+	/* zero mib counters */
+	for (i = 0; i < MIB_REG_CNT; i++)
+		writel_be(0, MIB_REG(i));
+
+	/* enable rx flow control */
+	setbits_be32(priv->base + ETH_RXCFG_REG, ETH_RXCFG_ENFLOW_MASK);
+
+	/* set max rx/tx length */
+	writel_be((ETH_MAX_MTU_SIZE << ETH_RXMAXLEN_SHIFT) &
+		  ETH_RXMAXLEN_MASK, priv->base + ETH_RXMAXLEN_REG);
+	writel_be((ETH_MAX_MTU_SIZE << ETH_TXMAXLEN_SHIFT) &
+		   ETH_TXMAXLEN_MASK, priv->base + ETH_TXMAXLEN_REG);
+
+	/* set correct transmit fifo watermark */
+	writel_be((ETH_TX_WATERMARK << ETH_TXWMARK_WM_SHIFT) &
+		  ETH_TXWMARK_WM_MASK, priv->base + ETH_TXWMARK_REG);
+
+	/* enable emac */
+	bcm6348_eth_mac_enable(priv);
+
+	/* clear interrupts */
+	writel_be(0, priv->base + ETH_IRMASK_REG);
+
+	return 0;
+}
+
+static void bcm6348_eth_stop(struct udevice *dev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* disable dma rx channel */
+	dma_disable(&priv->rx_dma);
+
+	/* disable dma tx channel */
+	dma_disable(&priv->tx_dma);
+
+	/* disable emac */
+	bcm6348_eth_mac_disable(priv);
+}
+
+static int bcm6348_eth_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	bool running = false;
+
+	/* check if emac is running */
+	if (readl_be(priv->base + ETH_CTL_REG) & ETH_CTL_ENABLE_MASK)
+		running = true;
+
+	/* disable emac */
+	if (running)
+		bcm6348_eth_mac_disable(priv);
+
+	/* set mac address */
+	writel_be((pdata->enetaddr[2] << 24) | (pdata->enetaddr[3]) << 16 |
+		  (pdata->enetaddr[4]) << 8 | (pdata->enetaddr[5]),
+		  priv->base + ETH_PML_REG(0));
+	writel_be((pdata->enetaddr[1]) | (pdata->enetaddr[0] << 8) |
+		  ETH_PMH_VALID_MASK, priv->base + ETH_PMH_REG(0));
+
+	/* enable emac */
+	if (running)
+		bcm6348_eth_mac_enable(priv);
+
+	return 0;
+}
+
+static const struct eth_ops bcm6348_eth_ops = {
+	.recv = bcm6348_eth_recv,
+	.send = bcm6348_eth_send,
+	.start = bcm6348_eth_start,
+	.stop = bcm6348_eth_stop,
+	.write_hwaddr = bcm6348_eth_write_hwaddr,
+};
+
+static const struct udevice_id bcm6348_eth_ids[] = {
+	{ .compatible = "brcm,bcm6348-enet", },
+	{ /* sentinel */ }
+};
+
+static int bcm6348_mdio_op(void __iomem *base, uint32_t data)
+{
+	/* make sure mii interrupt status is cleared */
+	writel_be(ETH_IR_MII_MASK, base + ETH_IR_REG);
+
+	/* issue mii op */
+	writel_be(data, base + MII_DAT_REG);
+
+	/* wait until emac is disabled */
+	return wait_for_bit_be32(base + ETH_IR_REG,
+				 ETH_IR_MII_MASK, true,
+				 ETH_TIMEOUT, false);
+}
+
+static int bcm6348_mdio_read(struct mii_dev *bus, int addr, int devaddr,
+			     int reg)
+{
+	void __iomem *base = bus->priv;
+	uint32_t val;
+
+	val = MII_DAT_OP_READ;
+	val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
+	val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
+	val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
+
+	if (bcm6348_mdio_op(base, val)) {
+		pr_err("%s: timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	val = readl_be(base + MII_DAT_REG) & MII_DAT_DATA_MASK;
+	val >>= MII_DAT_DATA_SHIFT;
+
+	return val;
+}
+
+static int bcm6348_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
+			      int reg, u16 value)
+{
+	void __iomem *base = bus->priv;
+	uint32_t val;
+
+	val = MII_DAT_OP_WRITE;
+	val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
+	val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
+	val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
+	val |= (value << MII_DAT_DATA_SHIFT) & MII_DAT_DATA_MASK;
+
+	if (bcm6348_mdio_op(base, val)) {
+		pr_err("%s: timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int bcm6348_mdio_init(const char *name, void __iomem *base)
+{
+	struct mii_dev *bus;
+
+	bus = mdio_alloc();
+	if (!bus) {
+		pr_err("%s: failed to allocate MDIO bus\n", __func__);
+		return -ENOMEM;
+	}
+
+	bus->read = bcm6348_mdio_read;
+	bus->write = bcm6348_mdio_write;
+	bus->priv = base;
+	snprintf(bus->name, sizeof(bus->name), "%s", name);
+
+	return mdio_register(bus);
+}
+
+static int bcm6348_phy_init(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	struct mii_dev *bus;
+
+	/* get mii bus */
+	bus = miiphy_get_dev_by_name(dev->name);
+
+	/* phy connect */
+	priv->phy_dev = phy_connect(bus, priv->phy_id, dev,
+				    pdata->phy_interface);
+	if (!priv->phy_dev) {
+		pr_err("%s: no phy device\n", __func__);
+		return -ENODEV;
+	}
+
+	priv->phy_dev->supported = (SUPPORTED_10baseT_Half |
+				    SUPPORTED_10baseT_Full |
+				    SUPPORTED_100baseT_Half |
+				    SUPPORTED_100baseT_Full |
+				    SUPPORTED_Autoneg |
+				    SUPPORTED_Pause |
+				    SUPPORTED_MII);
+	priv->phy_dev->advertising = priv->phy_dev->supported;
+
+	/* phy config */
+	phy_config(priv->phy_dev);
+
+	return 0;
+}
+
+static int bcm6348_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	void *blob = (void *)gd->fdt_blob;
+	int node = dev_of_offset(dev);
+	const char *phy_mode;
+	fdt_addr_t addr;
+	int phy_node, ret, i;
+
+	/* get base address */
+	addr = devfdt_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	/* get phy mode */
+	pdata->phy_interface = PHY_INTERFACE_MODE_NONE;
+	phy_mode = fdt_getprop(blob, node, "phy-mode", NULL);
+	if (phy_mode)
+		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_NONE)
+		return -ENODEV;
+
+	/* get phy */
+	phy_node = fdtdec_lookup_phandle(blob, node, "phy");
+	if (phy_node >= 0)
+		priv->phy_id = fdtdec_get_int(blob, phy_node, "reg", -1);
+	else
+		return -EINVAL;
+
+	/* get dma channels */
+	ret = dma_get_by_name(dev, "tx", &priv->tx_dma);
+	if (ret)
+		return -EINVAL;
+
+	ret = dma_get_by_name(dev, "rx", &priv->rx_dma);
+	if (ret)
+		return -EINVAL;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+		if (clk_enable(&clk))
+			pr_err("failed to enable clock %d\n", i);
+		clk_free(&clk);
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+		if (reset_deassert(&reset))
+			pr_err("failed to deassert reset %d\n", i);
+		reset_free(&reset);
+	}
+
+	/* get base addr */
+	priv->base = ioremap(addr, 0);
+	pdata->iobase = (phys_addr_t) priv->base;
+
+	/* disable emac */
+	bcm6348_eth_mac_disable(priv);
+
+	/* reset emac */
+	bcm6348_eth_mac_reset(priv);
+
+	/* select correct mii interface */
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_INTERNAL)
+		clrbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
+	else
+		setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
+
+	/* turn on mdc clock */
+	writel_be((0x1f << MII_SC_MDCFREQDIV_SHIFT) |
+		  MII_SC_PREAMBLE_EN_MASK, priv->base + MII_SC_REG);
+
+	/* set mib counters to not clear when read */
+	clrbits_be32(priv->base + MIB_CTL_REG, MIB_CTL_RDCLEAR_MASK);
+
+	/* initialize perfect match registers */
+	for (i = 0; i < ETH_PM_CNT; i++) {
+		writel_be(0, priv->base + ETH_PML_REG(i));
+		writel_be(0, priv->base + ETH_PMH_REG(i));
+	}
+
+	/* init mii bus */
+	ret = bcm6348_mdio_init(dev->name, priv->base);
+	if (ret)
+		return ret;
+
+	/* init phy */
+	ret = bcm6348_phy_init(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_eth) = {
+	.name = "bcm6348_eth",
+	.id = UCLASS_ETH,
+	.of_match = bcm6348_eth_ids,
+	.ops = &bcm6348_eth_ops,
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.priv_auto_alloc_size = sizeof(struct bcm6348_eth_priv),
+	.probe = bcm6348_eth_probe,
+};
diff --git a/include/configs/bmips_common.h b/include/configs/bmips_common.h
index 38bf7a272b..eb66512f67 100644
--- a/include/configs/bmips_common.h
+++ b/include/configs/bmips_common.h
@@ -7,6 +7,9 @@
 #ifndef __CONFIG_BMIPS_COMMON_H
 #define __CONFIG_BMIPS_COMMON_H
 
+/* ETH */
+#define CONFIG_PHY_RESET_DELAY		20
+
 /* UART */
 #define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200, \
 					  230400, 500000, 1500000 }
@@ -17,7 +20,7 @@
 
 /* Memory usage */
 #define CONFIG_SYS_MAXARGS		24
-#define CONFIG_SYS_MALLOC_LEN		(1024 * 1024)
+#define CONFIG_SYS_MALLOC_LEN		(2 * 1024 * 1024)
 #define CONFIG_SYS_BOOTPARAMS_LEN	(128 * 1024)
 #define CONFIG_SYS_CBSIZE		512
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 09/15] bmips: bcm6338: add support for bcm6348-enet
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (7 preceding siblings ...)
  2018-03-03  8:59   ` [U-Boot] [RFC v4 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 10/15] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6338.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6338.dtsi b/arch/mips/dts/brcm,bcm6338.dtsi
index 4125f71d9f..621278c9d1 100644
--- a/arch/mips/dts/brcm,bcm6338.dtsi
+++ b/arch/mips/dts/brcm,bcm6338.dtsi
@@ -145,5 +145,20 @@
 			dma-channels = <6>;
 			resets = <&periph_rst BCM6338_RST_DMAMEM>;
 		};
+
+		enet: ethernet at fffe2800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe2800 0x2dc>;
+			clocks = <&periph_clk BCM6338_CLK_ENET>;
+			resets = <&periph_rst BCM6338_RST_ENET>;
+			dmas = <&iudma BCM6338_DMA_ENET_RX>,
+			       <&iudma BCM6338_DMA_ENET_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
 	};
 };
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 10/15] bmips: enable f@st1704 enet support
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (8 preceding siblings ...)
  2018-03-03  8:59   ` [U-Boot] [RFC v4 09/15] bmips: bcm6338: " Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 11/15] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/sagem,f at st1704.dts     | 12 ++++++++++++
 configs/sagem_f at st1704_ram_defconfig |  9 ++++++++-
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/sagem,f at st1704.dts b/arch/mips/dts/sagem,f at st1704.dts
index dd0e5b8b7c..99d031f10a 100644
--- a/arch/mips/dts/sagem,f at st1704.dts
+++ b/arch/mips/dts/sagem,f at st1704.dts
@@ -40,6 +40,18 @@
 	};
 };
 
+&enet {
+	status = "okay";
+	phy = <&enetphy>;
+	phy-mode = "mii";
+
+	enetphy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio {
 	status = "okay";
 };
diff --git a/configs/sagem_f at st1704_ram_defconfig b/configs/sagem_f at st1704_ram_defconfig
index 0adcd46d51..1a640781b7 100644
--- a/configs/sagem_f at st1704_ram_defconfig
+++ b/configs/sagem_f at st1704_ram_defconfig
@@ -28,11 +28,15 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_SF=y
 CONFIG_CMD_SPI=y
-# CONFIG_CMD_NET is not set
+CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -41,6 +45,9 @@ CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_DM_RESET=y
 CONFIG_RESET_BCM6345=y
 # CONFIG_SPL_SERIAL_PRESENT is not set
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 11/15] bmips: bcm6348: add support for bcm6348-enet
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (9 preceding siblings ...)
  2018-03-03  8:59   ` [U-Boot] [RFC v4 10/15] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 12/15] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6348.dtsi | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6348.dtsi b/arch/mips/dts/brcm,bcm6348.dtsi
index d774c59665..e540865019 100644
--- a/arch/mips/dts/brcm,bcm6348.dtsi
+++ b/arch/mips/dts/brcm,bcm6348.dtsi
@@ -162,6 +162,32 @@
 			u-boot,dm-pre-reloc;
 		};
 
+		enet0: ethernet at fffe6000 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe6000 0x2dc>;
+			dmas = <&iudma BCM6348_DMA_ENET0_RX>,
+			       <&iudma BCM6348_DMA_ENET0_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		enet1: ethernet at fffe6800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe6800 0x2dc>;
+			dmas = <&iudma BCM6348_DMA_ENET1_RX>,
+			       <&iudma BCM6348_DMA_ENET1_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
 		iudma: dma-controller at fffe7000 {
 			compatible = "brcm,bcm6348-iudma";
 			reg = <0xfffe7000 0x1c>,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 12/15] bmips: enable ct-5361 enet support
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (10 preceding siblings ...)
  2018-03-03  8:59   ` [U-Boot] [RFC v4 11/15] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 13/15] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/comtrend,ct-5361.dts    | 12 ++++++++++++
 configs/comtrend_ct5361_ram_defconfig |  8 +++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/comtrend,ct-5361.dts b/arch/mips/dts/comtrend,ct-5361.dts
index 74dc09046c..a78aa877fc 100644
--- a/arch/mips/dts/comtrend,ct-5361.dts
+++ b/arch/mips/dts/comtrend,ct-5361.dts
@@ -35,6 +35,18 @@
 	};
 };
 
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/comtrend_ct5361_ram_defconfig b/configs/comtrend_ct5361_ram_defconfig
index 8b842606f5..0737772dd2 100644
--- a/configs/comtrend_ct5361_ram_defconfig
+++ b/configs/comtrend_ct5361_ram_defconfig
@@ -26,11 +26,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -38,6 +41,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6348_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 13/15] bmips: bcm6358: add support for bcm6348-enet
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (11 preceding siblings ...)
  2018-03-03  8:59   ` [U-Boot] [RFC v4 12/15] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 14/15] bmips: enable hg556a enet support Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 15/15] bmips: enable nb4-ser " Álvaro Fernández Rojas
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6358.dtsi | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6358.dtsi b/arch/mips/dts/brcm,bcm6358.dtsi
index 1468e4f63a..04329864c2 100644
--- a/arch/mips/dts/brcm,bcm6358.dtsi
+++ b/arch/mips/dts/brcm,bcm6358.dtsi
@@ -193,6 +193,34 @@
 			status = "disabled";
 		};
 
+		enet0: ethernet at fffe4000 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe4000 0x2dc>;
+			clocks = <&periph_clk BCM6358_CLK_ENET0>;
+			dmas = <&iudma BCM6358_DMA_ENET0_RX>,
+			       <&iudma BCM6358_DMA_ENET0_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		enet1: ethernet at fffe4800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe4800 0x2dc>;
+			clocks = <&periph_clk BCM6358_CLK_ENET1>;
+			dmas = <&iudma BCM6358_DMA_ENET1_RX>,
+			       <&iudma BCM6358_DMA_ENET1_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
 		iudma: dma-controller at fffe5000 {
 			compatible = "brcm,bcm6348-iudma";
 			reg = <0xfffe5000 0x24>,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 14/15] bmips: enable hg556a enet support
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (12 preceding siblings ...)
  2018-03-03  8:59   ` [U-Boot] [RFC v4 13/15] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  2018-03-03  8:59   ` [U-Boot] [RFC v4 15/15] bmips: enable nb4-ser " Álvaro Fernández Rojas
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/huawei,hg556a.dts     | 12 ++++++++++++
 configs/huawei_hg556a_ram_defconfig |  8 +++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/huawei,hg556a.dts b/arch/mips/dts/huawei,hg556a.dts
index a1e9c15ab9..2f99e0905c 100644
--- a/arch/mips/dts/huawei,hg556a.dts
+++ b/arch/mips/dts/huawei,hg556a.dts
@@ -94,6 +94,18 @@
 	status = "okay";
 };
 
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/huawei_hg556a_ram_defconfig b/configs/huawei_hg556a_ram_defconfig
index 7f7f34ed61..c7c7c6554f 100644
--- a/configs/huawei_hg556a_ram_defconfig
+++ b/configs/huawei_hg556a_ram_defconfig
@@ -26,11 +26,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -38,6 +41,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6358_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 15/15] bmips: enable nb4-ser enet support
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (13 preceding siblings ...)
  2018-03-03  8:59   ` [U-Boot] [RFC v4 14/15] bmips: enable hg556a enet support Álvaro Fernández Rojas
@ 2018-03-03  8:59   ` Álvaro Fernández Rojas
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  8:59 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/sfr,nb4-ser.dts     | 24 ++++++++++++++++++++++++
 configs/sfr_nb4-ser_ram_defconfig |  8 +++++++-
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/sfr,nb4-ser.dts b/arch/mips/dts/sfr,nb4-ser.dts
index 473372faa1..73db45f9ea 100644
--- a/arch/mips/dts/sfr,nb4-ser.dts
+++ b/arch/mips/dts/sfr,nb4-ser.dts
@@ -54,6 +54,30 @@
 	status = "okay";
 };
 
+&enet0 {
+	status = "okay";
+	phy = <&enet0phy>;
+	phy-mode = "internal";
+
+	enet0phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/sfr_nb4-ser_ram_defconfig b/configs/sfr_nb4-ser_ram_defconfig
index fc323d879d..07b49a1a77 100644
--- a/configs/sfr_nb4-ser_ram_defconfig
+++ b/configs/sfr_nb4-ser_ram_defconfig
@@ -27,11 +27,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -40,6 +43,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6358_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 03/15] dma: add bcm6348-iudma support
  2018-02-23 16:57         ` Grygorii Strashko
@ 2018-03-03  9:06           ` Álvaro Fernández Rojas
  0 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-03  9:06 UTC (permalink / raw)
  To: u-boot

Hi Grygorii,

El 23/02/2018 a las 17:57, Grygorii Strashko escribió:
> Hi
>
> thanks for your comments.
>
> On 02/22/2018 02:48 PM, Álvaro Fernández Rojas wrote:
>> El 22/02/2018 a las 20:50, Grygorii Strashko escribió:
>>> On 02/21/2018 10:10 AM, Álvaro Fernández Rojas wrote:
>>>> BCM6348 IUDMA controller is present on multiple BMIPS (BCM63xx) SoCs.
>>>>
>>>> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
>>>> ---
>>>>     v3: no changes
>>>>     v2: Fix dma rx burst config and select DMA_CHANNELS.
>>>>
>>>>     drivers/dma/Kconfig         |   9 +
>>>>     drivers/dma/Makefile        |   1 +
>>>>     drivers/dma/bcm6348-iudma.c | 505
>>>> ++++++++++++++++++++++++++++++++++++++++++++
>>>>     3 files changed, 515 insertions(+)
>>>>     create mode 100644 drivers/dma/bcm6348-iudma.c
>>>>
>>> [...]
>>>> +static int bcm6348_iudma_enable(struct dma *dma)
>>>> +{
>>>> +    struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
>>>> +    struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
>>>> +    struct bcm6348_dma_desc *dma_desc;
>>>> +    uint8_t i;
>>>> +
>>>> +    /* init dma rings */
>>>> +    dma_desc = ch_priv->dma_ring;
>>>> +    for (i = 0; i < ch_priv->dma_ring_size; i++) {
>>>> +        if (bcm6348_iudma_chan_is_rx(dma->id)) {
>>>> +            dma_desc->status = DMAD_ST_OWN_MASK;
>>>> +            dma_desc->length = PKTSIZE_ALIGN;
>>>> +            dma_desc->address = virt_to_phys(net_rx_packets[i]);
>>> You are filling RX queue/ring with buffers defined in Net core.
>>> Does it mean that this DMA driver will not be usable for other
>>> purposes, as
>>> Net can be compiled out?
>> As far as I know, and depending on the specific SoC, BCM63xx IUDMA is
>> used for Ethernet, USB (device only) and xDSL.
>> So yes, in u-boot it will be used for ethernet only.
>> BTW, my first attempt didn't use net_rx_packets, but I saw that in
>> pic32_eth implementation and dropped the dma specific buffers. I will
>> add them again ;).
> it is really net specific :)
>
>>> Wouldn't it be reasonable to have some sort of .receive_prepare()
>>> callback in
>>> DMA dma_ops, so DMA user can control which buffers to push in RX DMA
>>> channel?
>>> And it also can be used in eth_ops.free_pkt() callback (see below).
>> Yes, probably, but maybe we can achieve that without adding another call.
> I'm looking at this patch set from our HW point of view. In my case,
> DMA channel can be used with different IPs (not only networking), so
> it would be really great if DMA user can pass RX buffers in DMA driver -
> network driver can use net_rx_packets, other drivers might use own buffers.
> So hard-codding RX buffers in DMA driver looks like not a good choice.
>
>>>> +
>>>> +    /* flush cache */
>>>> +    flush_dcache_range((ulong)dma_desc,
>>>> +        ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
>>> Could you clarify pls, if you do return dma_desc to RX ring here or not?
>> Yes.
>>> if yes, wouldn't it cause potential problem on Net RX path
>>>          ret = eth_get_ops(current)->recv(current, flags, &packet);
>>> ^^ (1) here buffer will be received from DMA ( and pushed back to RX
>>> ring ?? )
>>>
>>>          flags = 0;
>>>          if (ret > 0)
>>>              net_process_received_packet(packet, ret);
>>> ^^ (2) here it will be passed in Net stack
>>>
>>>          if (ret >= 0 && eth_get_ops(current)->free_pkt)
>>>              eth_get_ops(current)->free_pkt(current, packet, ret);
>>> ^^ at this point it should be safe to return buffer in DMA RX ring.
>>>
>>>          if (ret <= 0)
>>>              break;
>>>
>>> Can DMA overwrite packet after point (1) while packet is still
>>> processed (2)?
>> I don't think so, because as far as I know u-boot is not processing more
>> than one packet at once, is it?
> u-boot can't process more than one packet, but dma does. if buffer returned
> to DMA and there are some traffic on the line - DMA can potentially refill
> all buffers in its RX ring while u-boot still processing one packet.
I just sent a new version of the patches which doesn't use 
net_rx_packets in bcm6348-iudma.
However, after several tests it turns out that dma received buffers must 
be processed as soon as possible in order to avoid flow control issues.
Considering that, releasing the buffer by using free_pkt after the 
packet is processed isn't a valid option, since it makes ethernet unusable.
That's why I decided to allocate a dynamic buffer on bcm6348-iudma, 
saving the received packets on net_rx_packets and immediately returning 
the dma descriptor to the RX ring.

However, you can still add dma_receive_prepare to dma ops if you need it 
for your HW.
>
>
>> But yeah, I see your point and if it does process more than one packet
>> at once this is not the proper way to do that.
>> I will use free_pkt in next version and lock the packet until it's
>> processed.
>
Regards,
Álvaro.

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 01/15] dma: move dma_ops to dma-uclass.h
  2018-02-22 16:18     ` Simon Glass
@ 2018-03-05 19:35       ` Grygorii Strashko
  2018-03-05 20:06         ` Álvaro Fernández Rojas
  0 siblings, 1 reply; 106+ messages in thread
From: Grygorii Strashko @ 2018-03-05 19:35 UTC (permalink / raw)
  To: u-boot



On 02/22/2018 10:18 AM, Simon Glass wrote:
> On 21 February 2018 at 09:10, Álvaro Fernández Rojas <noltari@gmail.com> wrote:
>> Move dma_ops to a separate header file, following other uclass implementations.
>> While doing so, this patch also improves dma_ops documentation.
>>
>> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
>> ---
>>   v3: Introduce changes reported by Simon Glass:
>>    - Improve dma-uclass.h documentation.
>>    - Switch to live tree API.
>>
>>   drivers/dma/dma-uclass.c |  3 ++-
>>   include/dma-uclass.h     | 39 +++++++++++++++++++++++++++++++++++++++
>>   include/dma.h            | 22 ----------------------
>>   3 files changed, 41 insertions(+), 23 deletions(-)
>>   create mode 100644 include/dma-uclass.h
> 
> Reviewed-by: Simon Glass <sjg@chromium.org>

this patch will break build of existing DMA drivers, as
the do not have #include <dma-uclass.h>.

drivers/dma/ti-edma3.c:563:21: error: variable 'ti_edma3_ops' has initializer but incomplete type
 static const struct dma_ops ti_edma3_ops = {
                     ^~~~~~~
drivers/dma/ti-edma3.c:564:2: error: unknown field 'transfer' specified in initializer
  .transfer = ti_edma3_transfer,
  ^
drivers/dma/ti-edma3.c:564:14: warning: excess elements in struct initializer
  .transfer = ti_edma3_transfer,
              ^~~~~~~~~~~~~~~~~
drivers/dma/ti-edma3.c:564:14: note: (near initialization for 'ti_edma3_ops')
drivers/dma/ti-edma3.c:563:29: error: storage size of 'ti_edma3_ops' isn't known
 static const struct dma_ops ti_edma3_ops = {
                             ^~~~~~~~~~~~
make[1]: *** [drivers/dma/ti-edma3.o] Error 1


-- 
regards,
-grygorii

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v4 01/15] dma: move dma_ops to dma-uclass.h
  2018-03-03  8:59   ` [U-Boot] [RFC v4 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
@ 2018-03-05 19:38     ` Grygorii Strashko
  0 siblings, 0 replies; 106+ messages in thread
From: Grygorii Strashko @ 2018-03-05 19:38 UTC (permalink / raw)
  To: u-boot

Hi

On 03/03/2018 02:59 AM, Álvaro Fernández Rojas wrote:
> Move dma_ops to a separate header file, following other uclass implementations.
> While doing so, this patch also improves dma_ops documentation.
> 
> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
> Reviewed-by: Simon Glass <sjg@chromium.org>
> ---
>   v4: no changes
>   v3: Introduce changes reported by Simon Glass:
>    - Improve dma-uclass.h documentation.
>    - Switch to live tree API.
> 
>   drivers/dma/dma-uclass.c |  3 ++-
>   include/dma-uclass.h     | 39 +++++++++++++++++++++++++++++++++++++++
>   include/dma.h            | 22 ----------------------
>   3 files changed, 41 insertions(+), 23 deletions(-)
>   create mode 100644 include/dma-uclass.h
> 

I've sent the same comment for prev patch version also.


this patch will break build of existing DMA drivers, as
the do not have #include <dma-uclass.h>.

drivers/dma/ti-edma3.c:563:21: error: variable 'ti_edma3_ops' has initializer but incomplete type
 static const struct dma_ops ti_edma3_ops = {
                     ^~~~~~~
drivers/dma/ti-edma3.c:564:2: error: unknown field 'transfer' specified in initializer
  .transfer = ti_edma3_transfer,
  ^
drivers/dma/ti-edma3.c:564:14: warning: excess elements in struct initializer
  .transfer = ti_edma3_transfer,
              ^~~~~~~~~~~~~~~~~
drivers/dma/ti-edma3.c:564:14: note: (near initialization for 'ti_edma3_ops')
drivers/dma/ti-edma3.c:563:29: error: storage size of 'ti_edma3_ops' isn't known
 static const struct dma_ops ti_edma3_ops = {
                             ^~~~~~~~~~~~
make[1]: *** [drivers/dma/ti-edma3.o] Error 1

-- 
regards,
-grygorii

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support
  2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                   ` (17 preceding siblings ...)
  2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
@ 2018-03-05 20:05 ` Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
                     ` (14 more replies)
  18 siblings, 15 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

In order to add bcm6348-enet support, dma-uclass must be extended to support
dma channels and reworked to operate like the other dm uclass (clk, reset...).

v5: Fix issues reported by Grygorii Strashko and other fixes:
 - Fix build of ti-edma3.
 - Remove unused bcm6348-iudma defines.
 - Increment bcm6348-iudma rx descriptors.
 - Fix bcm6348-iudma flow control issues.
 - bcm6348-iudma error checking now depends on hw.
 - Remove unneeded bcm6348-iudma interrupts.
 - Receive as much packets as possible from bcm6348-eth and cache them in
 net_rx_packets. This is needed in order to fix flow control issues.
v4: Fix issues reported by Grygorii Strashko and other fixes:
 - Remove usage of net_rx_packets as buffer from bcm6348-iudma.
 - Allocate dynamic rx buffer on bcm6348-iudma.
 - Copy received dma buffer to net_rx_packets in order to avoid possible
 dma overwrites.
 - Check dma errors and discard invalid packets.
 - Reset dma rx channel when sending a new packet to prevent flow control
 issues.
 - Fix packet casting on bcm6348_eth_recv/send.
v3: Introduce changes reported by Simon Glass:
 - Improve dma-uclass.h documentation.
 - Switch to live tree API.
v2: Introduce changes reported by Vignesh:
 - Respect current dma implementation.
 - Let dma_memcpy find a compatible dma device.
Other changes:
 - Fix bcm6348-iudma rx burst config.

Álvaro Fernández Rojas (15):
  dma: move dma_ops to dma-uclass.h
  dma: add channels support
  dma: add bcm6348-iudma support
  bmips: bcm6338: add bcm6348-iudma support
  bmips: bcm6348: add bcm6348-iudma support
  bmips: bcm6358: add bcm6348-iudma support
  phy: add support for internal phys
  net: add support for bcm6348-enet
  bmips: bcm6338: add support for bcm6348-enet
  bmips: enable f at st1704 enet support
  bmips: bcm6348: add support for bcm6348-enet
  bmips: enable ct-5361 enet support
  bmips: bcm6358: add support for bcm6348-enet
  bmips: enable hg556a enet support
  bmips: enable nb4-ser enet support

 arch/mips/dts/brcm,bcm6338.dtsi       |  29 ++
 arch/mips/dts/brcm,bcm6348.dtsi       |  42 +++
 arch/mips/dts/brcm,bcm6358.dtsi       |  46 +++
 arch/mips/dts/comtrend,ct-5361.dts    |  12 +
 arch/mips/dts/huawei,hg556a.dts       |  12 +
 arch/mips/dts/sagem,f at st1704.dts      |  12 +
 arch/mips/dts/sfr,nb4-ser.dts         |  24 ++
 configs/comtrend_ct5361_ram_defconfig |   8 +-
 configs/huawei_hg556a_ram_defconfig   |   8 +-
 configs/sagem_f at st1704_ram_defconfig  |   9 +-
 configs/sfr_nb4-ser_ram_defconfig     |   8 +-
 drivers/dma/Kconfig                   |  16 +
 drivers/dma/Makefile                  |   1 +
 drivers/dma/bcm6348-iudma.c           | 532 +++++++++++++++++++++++++++++++
 drivers/dma/dma-uclass.c              | 190 ++++++++++-
 drivers/dma/ti-edma3.c                |   2 +-
 drivers/net/Kconfig                   |  10 +
 drivers/net/Makefile                  |   1 +
 drivers/net/bcm6348-eth.c             | 575 ++++++++++++++++++++++++++++++++++
 include/configs/bmips_common.h        |   5 +-
 include/dma-uclass.h                  | 117 +++++++
 include/dma.h                         | 196 ++++++++++--
 include/dt-bindings/dma/bcm6338-dma.h |  15 +
 include/dt-bindings/dma/bcm6348-dma.h |  17 +
 include/dt-bindings/dma/bcm6358-dma.h |  17 +
 include/phy.h                         |   2 +
 26 files changed, 1869 insertions(+), 37 deletions(-)
 create mode 100644 drivers/dma/bcm6348-iudma.c
 create mode 100644 drivers/net/bcm6348-eth.c
 create mode 100644 include/dma-uclass.h
 create mode 100644 include/dt-bindings/dma/bcm6338-dma.h
 create mode 100644 include/dt-bindings/dma/bcm6348-dma.h
 create mode 100644 include/dt-bindings/dma/bcm6358-dma.h

-- 
2.11.0

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 01/15] dma: move dma_ops to dma-uclass.h
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-06 15:10     ` Grygorii Strashko
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 02/15] dma: add channels support Álvaro Fernández Rojas
                     ` (13 subsequent siblings)
  14 siblings, 1 reply; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Move dma_ops to a separate header file, following other uclass implementations.
While doing so, this patch also improves dma_ops documentation.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---
 v5: fix build of ti-edma3 (reported by Grygorii Strashko) and 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/dma-uclass.c |  2 +-
 drivers/dma/ti-edma3.c   |  2 +-
 include/dma-uclass.h     | 39 +++++++++++++++++++++++++++++++++++++++
 include/dma.h            | 22 ----------------------
 4 files changed, 41 insertions(+), 24 deletions(-)
 create mode 100644 include/dma-uclass.h

diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
index 3d0ce22fbc..faa27a3a56 100644
--- a/drivers/dma/dma-uclass.c
+++ b/drivers/dma/dma-uclass.c
@@ -10,10 +10,10 @@
  */
 
 #include <common.h>
-#include <dma.h>
 #include <dm.h>
 #include <dm/uclass-internal.h>
 #include <dm/device-internal.h>
+#include <dma-uclass.h>
 #include <errno.h>
 
 DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/dma/ti-edma3.c b/drivers/dma/ti-edma3.c
index 852c9e1fd7..64f9a61b49 100644
--- a/drivers/dma/ti-edma3.c
+++ b/drivers/dma/ti-edma3.c
@@ -12,7 +12,7 @@
 #include <asm/io.h>
 #include <common.h>
 #include <dm.h>
-#include <dma.h>
+#include <dma-uclass.h>
 #include <asm/omap_common.h>
 #include <asm/ti-common/ti-edma3.h>
 
diff --git a/include/dma-uclass.h b/include/dma-uclass.h
new file mode 100644
index 0000000000..3429f65ec4
--- /dev/null
+++ b/include/dma-uclass.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DMA_UCLASS_H
+#define _DMA_UCLASS_H
+
+/* See dma.h for background documentation. */
+
+#include <dma.h>
+
+/*
+ * struct dma_ops - Driver model DMA operations
+ *
+ * The uclass interface is implemented by all DMA devices which use
+ * driver model.
+ */
+struct dma_ops {
+	/**
+	 * transfer() - Issue a DMA transfer. The implementation must
+	 *   wait until the transfer is done.
+	 *
+	 * @dev: The DMA device
+	 * @direction: direction of data transfer (should be one from
+	 *   enum dma_direction)
+	 * @dst: The destination pointer.
+	 * @src: The source pointer.
+	 * @len: Length of the data to be copied (number of bytes).
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*transfer)(struct udevice *dev, int direction, void *dst,
+			void *src, size_t len);
+};
+
+#endif /* _DMA_UCLASS_H */
diff --git a/include/dma.h b/include/dma.h
index 71fa77f2ea..89320f10d9 100644
--- a/include/dma.h
+++ b/include/dma.h
@@ -28,28 +28,6 @@ enum dma_direction {
 #define DMA_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, should be
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 02/15] dma: add channels support
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-07 21:27     ` Joe Hershberger
                       ` (2 more replies)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
                     ` (12 subsequent siblings)
  14 siblings, 3 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

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 <noltari@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---
 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, <www.ti.com>
- *
- * Author: Mugunthan V N <mugunthanvnm@ti.com>
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
  *
  * SPDX-License-Identifier:     GPL-2.0+
  */
 
 #include <common.h>
 #include <dm.h>
-#include <dm/uclass-internal.h>
-#include <dm/device-internal.h>
+#include <dm/read.h>
 #include <dma-uclass.h>
+#include <dt-structs.h>
 #include <errno.h>
 
 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, &dma->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,
+					 &args);
+	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, &dev_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, &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);
+	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, 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 3429f65ec4..b334adb68b 100644
--- a/include/dma-uclass.h
+++ b/include/dma-uclass.h
@@ -13,6 +13,8 @@
 
 #include <dma.h>
 
+struct ofnode_phandle_args;
+
 /*
  * struct dma_ops - Driver model DMA operations
  *
@@ -20,6 +22,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 ofnode_phandle_args *args);
+	/**
+	 * request - Request a translated DMA.
+	 *
+	 * The DMA core calls this function as the second step in
+	 * implementing a client's dma_get_by_*() call, following a successful
+	 * xxx_xlate() call, or as the only step in implementing a client's
+	 * dma_request() call.
+	 *
+	 * @dma: The DMA struct to request; this has been filled in by
+	 *   a previoux xxx_xlate() function call, or by the caller of
+	 *   dma_request().
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*request)(struct dma *dma);
+	/**
+	 * free - Free a previously requested dma.
+	 *
+	 * This is the implementation of the client dma_free() API.
+	 *
+	 * @dma: The DMA to free.
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*free)(struct dma *dma);
+	/**
+	 * enable() - Enable a DMA Channel.
+	 *
+	 * @dma: The DMA Channel to manipulate.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*enable)(struct dma *dma);
+	/**
+	 * disable() - Disable a DMA Channel.
+	 *
+	 * @dma: The DMA Channel to manipulate.
+	 * @return zero on success, or -ve error code.
+	 */
+	int (*disable)(struct dma *dma);
+	/**
+	 * 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);
+#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, <www.ti.com>
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
+ * Written by Mugunthan V N <mugunthanvnm@ti.com>
  *
  * SPDX-License-Identifier:     GPL-2.0+
  */
@@ -8,6 +9,9 @@
 #ifndef _DMA_H_
 #define _DMA_H_
 
+#include <linux/errno.h>
+#include <linux/types.h>
+
 /*
  * 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 provider. A provider will
+ * often implement multiple separate DMAs, since the hardware it manages
+ * often has this capability. dma_uclass.h describes the interface which
+ * DMA providers must implement.
+ *
+ * DMA consumers/clients are the HW modules driven by the DMA channels. This
+ * header file describes the API used by drivers for those HW modules.
+ */
+
+struct udevice;
+
+/**
+ * struct dma - A handle to (allowing control of) a single DMA.
+ *
+ * Clients provide storage for DMA handles. The content of the structure is
+ * managed solely by the DMA API and DMA drivers. A DMA struct is
+ * initialized by "get"ing the DMA struct. The DMA struct is passed to all
+ * other DMA APIs to identify which DMA channel to operate upon.
+ *
+ * @dev: The device which implements the DMA channel.
+ * @id: The DMA channel ID within the provider.
+ *
+ * Currently, the DMA API assumes that a single integer ID is enough to
+ * identify and configure any DMA channel for any DMA provider. If this
+ * assumption becomes invalid in the future, the struct could be expanded to
+ * either (a) add more fields to allow DMA providers to store additional
+ * information, or (b) replace the id field with an opaque pointer, which the
+ * provider would dynamically allocated during its .of_xlate op, and process
+ * during is .request op. This may require the addition of an extra op to clean
+ * up the allocation.
+ */
+struct dma {
+	struct udevice *dev;
+	/*
+	 * Written by of_xlate. We assume a single id is enough for now. In the
+	 * future, we might add more fields here.
+	 */
+	unsigned long id;
+};
+
+# if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DMA)
+struct phandle_1_arg;
+int dma_get_by_index_platdata(struct udevice *dev, int index,
+			      struct phandle_1_arg *cells, struct dma *dma);
+
+/**
+ * dma_get_by_index - Get/request a DMA by integer index.
+ *
+ * This looks up and requests a DMA. The index is relative to the client
+ * device; each device is assumed to have n DMAs associated with it somehow,
+ * and this function finds and requests one of them. The mapping of client
+ * device DMA indices to provider DMAs may be via device-tree properties,
+ * board-provided mapping tables, or some other mechanism.
+ *
+ * @dev:	The client device.
+ * @index:	The index of the DMA to request, within the client's list of
+ *		DMA channels.
+ * @dma:	A pointer to a DMA struct to initialize.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_get_by_index(struct udevice *dev, int index, struct dma *dma);
+
+/**
+ * dma_get_by_name - Get/request a DMA by name.
+ *
+ * This looks up and requests a DMA. The name is relative to the client
+ * device; each device is assumed to have n DMAs associated with it somehow,
+ * and this function finds and requests one of them. The mapping of client
+ * device DMA names to provider DMAs may be via device-tree properties,
+ * board-provided mapping tables, or some other mechanism.
+ *
+ * @dev:	The client device.
+ * @name:	The name of the DMA to request, within the client's list of
+ *		DMA channels.
+ * @dma:	A pointer to a DMA struct to initialize.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma);
+# else
+static inline int dma_get_by_index(struct udevice *dev, int index,
+				   struct dma *dma)
+{
+	return -ENOSYS;
+}
+
+static inline int dma_get_by_name(struct udevice *dev, const char *name,
+			   struct dma *dma)
+{
+	return -ENOSYS;
+}
+# endif
+
+/**
+ * dma_request - Request a DMA by provider-specific ID.
+ *
+ * This requests a DMA using a provider-specific ID. Generally, this function
+ * should not be used, since dma_get_by_index/name() provide an interface that
+ * better separates clients from intimate knowledge of DMA providers.
+ * However, this function may be useful in core SoC-specific code.
+ *
+ * @dev: The DMA provider device.
+ * @dma: A pointer to a DMA struct to initialize. The caller must
+ *	 have already initialized any field in this struct which the
+ *	 DMA provider uses to identify the DMA channel.
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_request(struct udevice *dev, struct dma *dma);
+
+/**
+ * dma_free - Free a previously requested DMA.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return 0 if OK, or a negative error code.
+ */
+int dma_free(struct dma *dma);
+
+/**
+ * dma_enable() - Enable (turn on) a DMA channel.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return zero on success, or -ve error code.
+ */
+int dma_enable(struct dma *dma);
+
+/**
+ * dma_disable() - Disable (turn off) a DMA channel.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @return zero on success, or -ve error code.
+ */
+int dma_disable(struct dma *dma);
+
+/**
+ * dma_receive() - Receive a DMA transfer.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @dst: The destination pointer.
+ * @return zero on success, or -ve error code.
+ */
+int dma_receive(struct dma *dma, void **dst);
+
+/**
+ * dma_send() - Send a DMA transfer.
+ *
+ * @dma: A DMA struct that was previously successfully requested by
+ *	 dma_request/get_by_*().
+ * @src: The source pointer.
+ * @len: Length of the data to be sent (number of bytes).
+ * @return zero on success, or -ve error code.
+ */
+int dma_send(struct dma *dma, void *src, size_t len);
+#endif /* CONFIG_DMA_CHANNELS */
+
 /*
  * dma_get_device - get a DMA device which supports transfer
  * type of transfer_type
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 03/15] dma: add bcm6348-iudma support
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 02/15] dma: add channels support Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 04/15] bmips: bcm6338: " Álvaro Fernández Rojas
                     ` (11 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

BCM6348 IUDMA controller is present on multiple BMIPS (BCM63xx) SoCs.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: Several fixes and improvements:
  - Remove unused defines.
  - Increment rx descriptors.
  - Fix flow control issues.
  - Error checking now depends on hw.
  - Remove unneeded interrupts.
 v4: Fix issues reported by Grygorii Strashko and other fixes:
  - Remove usage of net_rx_packets as buffer.
  - Allocate dynamic rx buffer.
  - Check dma errors and discard invalid packets.
 v3: no changes
 v2: Fix dma rx burst config and select DMA_CHANNELS.

 drivers/dma/Kconfig         |   9 +
 drivers/dma/Makefile        |   1 +
 drivers/dma/bcm6348-iudma.c | 532 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 542 insertions(+)
 create mode 100644 drivers/dma/bcm6348-iudma.c

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 21b2c0dcaa..9afa158b51 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -19,6 +19,15 @@ config DMA_CHANNELS
 	  Enable channels support for DMA. Some DMA controllers have multiple
 	  channels which can either transfer data to/from different devices.
 
+config BCM6348_IUDMA
+	bool "BCM6348 IUDMA driver"
+	depends on ARCH_BMIPS
+	select DMA_CHANNELS
+	help
+	  Enable the BCM6348 IUDMA driver.
+	  This driver support data transfer from devices to
+	  memory and from memory to devices.
+
 config TI_EDMA3
 	bool "TI EDMA3 driver"
 	help
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 39b78b2a3d..b2b4147349 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_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_BCM6348_IUDMA) += bcm6348-iudma.o
 obj-$(CONFIG_FSL_DMA) += fsl_dma.o
 obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
 obj-$(CONFIG_TI_EDMA3) += ti-edma3.o
diff --git a/drivers/dma/bcm6348-iudma.c b/drivers/dma/bcm6348-iudma.c
new file mode 100644
index 0000000000..962d7ae3e5
--- /dev/null
+++ b/drivers/dma/bcm6348-iudma.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/dma/bcm63xx-iudma.c:
+ *	Copyright (C) 2015 Simon Arlott <simon@fire.lp0.eu>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
+ *	Copyright (C) 2000-2010 Broadcom Corporation
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/bcmdrivers/opensource/net/enet/impl4/bcmenet.c:
+ *	Copyright (C) 2010 Broadcom Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma-uclass.h>
+#include <memalign.h>
+#include <reset.h>
+#include <asm/io.h>
+
+#define DMA_RX_DESC	6
+#define DMA_TX_DESC	1
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ALIGN_END_ADDR(type, ptr, size)	\
+	((unsigned long)(ptr) + roundup((size) * sizeof(type), \
+	 ARCH_DMA_MINALIGN))
+
+/* DMA Channels */
+#define DMA_CHAN_FLOWC(x)		((x) >> 1)
+#define DMA_CHAN_MAX			16
+#define DMA_CHAN_SIZE			0x10
+#define DMA_CHAN_TOUT			500
+
+/* DMA Global Configuration register */
+#define DMA_CFG_REG			0x00
+#define  DMA_CFG_ENABLE_SHIFT		0
+#define  DMA_CFG_ENABLE_MASK		(1 << DMA_CFG_ENABLE_SHIFT)
+#define  DMA_CFG_FLOWC_ENABLE(x)	BIT(DMA_CHAN_FLOWC(x) + 1)
+#define  DMA_CFG_NCHANS_SHIFT		24
+#define  DMA_CFG_NCHANS_MASK		(0xf << DMA_CFG_NCHANS_SHIFT)
+
+/* DMA Global Flow Control registers */
+#define DMA_FLOWC_THR_LO_REG(x)		(0x04 + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_THR_HI_REG(x)		(0x08 + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_ALLOC_REG(x)		(0x0c + DMA_CHAN_FLOWC(x) * 0x0c)
+#define  DMA_FLOWC_ALLOC_FORCE_SHIFT	31
+#define  DMA_FLOWC_ALLOC_FORCE_MASK	(1 << DMA_FLOWC_ALLOC_FORCE_SHIFT)
+
+/* DMA Global Reset register */
+#define DMA_RST_REG			0x34
+#define  DMA_RST_CHAN_SHIFT		0
+#define  DMA_RST_CHAN_MASK(x)		(1 << x)
+
+/* DMA Channel Configuration register */
+#define DMAC_CFG_REG(x)			(DMA_CHAN_SIZE * (x) + 0x00)
+#define  DMAC_CFG_ENABLE_SHIFT		0
+#define  DMAC_CFG_ENABLE_MASK		(1 << DMAC_CFG_ENABLE_SHIFT)
+#define  DMAC_CFG_PKT_HALT_SHIFT	1
+#define  DMAC_CFG_PKT_HALT_MASK		(1 << DMAC_CFG_PKT_HALT_SHIFT)
+#define  DMAC_CFG_BRST_HALT_SHIFT	2
+#define  DMAC_CFG_BRST_HALT_MASK	(1 << DMAC_CFG_BRST_HALT_SHIFT)
+
+/* DMA Channel Max Burst Length register */
+#define DMAC_BURST_REG(x)		(DMA_CHAN_SIZE * (x) + 0x0c)
+
+/* DMA SRAM Descriptor Ring Start register */
+#define DMAS_RSTART_REG(x)		(DMA_CHAN_SIZE * (x) + 0x00)
+
+/* DMA SRAM State/Bytes done/ring offset register */
+#define DMAS_STATE_DATA_REG(x)		(DMA_CHAN_SIZE * (x) + 0x04)
+
+/* DMA SRAM Buffer Descriptor status and length register */
+#define DMAS_DESC_LEN_STATUS_REG(x)	(DMA_CHAN_SIZE * (x) + 0x08)
+
+/* DMA SRAM Buffer Descriptor status and length register */
+#define DMAS_DESC_BASE_BUFPTR_REG(x)	(DMA_CHAN_SIZE * (x) + 0x0c)
+
+struct bcm6348_dma_desc {
+	uint16_t length;
+
+	uint16_t status;
+#define DMAD_ST_CRC_SHIFT		8
+#define DMAD_ST_CRC_MASK		(1 << DMAD_ST_CRC_SHIFT)
+#define DMAD_ST_WRAP_SHIFT		12
+#define DMAD_ST_WRAP_MASK		(1 << DMAD_ST_WRAP_SHIFT)
+#define DMAD_ST_SOP_SHIFT		13
+#define DMAD_ST_SOP_MASK		(1 << DMAD_ST_SOP_SHIFT)
+#define DMAD_ST_EOP_SHIFT		14
+#define DMAD_ST_EOP_MASK		(1 << DMAD_ST_EOP_SHIFT)
+#define DMAD_ST_OWN_SHIFT		15
+#define DMAD_ST_OWN_MASK		(1 << DMAD_ST_OWN_SHIFT)
+
+#define DMAD6348_ST_OV_ERR_SHIFT	0
+#define DMAD6348_ST_OV_ERR_MASK		(1 << DMAD6348_ST_OV_ERR_SHIFT)
+#define DMAD6348_ST_CRC_ERR_SHIFT	1
+#define DMAD6348_ST_CRC_ERR_MASK	(1 << DMAD6348_ST_CRC_ERR_SHIFT)
+#define DMAD6348_ST_RX_ERR_SHIFT	2
+#define DMAD6348_ST_RX_ERR_MASK		(1 << DMAD6348_ST_RX_ERR_SHIFT)
+#define DMAD6348_ST_OS_ERR_SHIFT	4
+#define DMAD6348_ST_OS_ERR_MASK		(1 << DMAD6348_ST_OS_ERR_SHIFT)
+#define DMAD6348_ST_UN_ERR_SHIFT	9
+#define DMAD6348_ST_UN_ERR_MASK		(1 << DMAD6348_ST_UN_ERR_SHIFT)
+
+	uint32_t address;
+} __attribute__((aligned(1)));
+
+struct bcm6348_chan_priv {
+	void __iomem *dma_buff;
+	void __iomem *dma_ring;
+	uint8_t dma_ring_size;
+	uint8_t desc_id;
+};
+
+struct bcm6348_iudma_hw {
+	uint16_t err_mask;
+};
+
+struct bcm6348_iudma_priv {
+	const struct bcm6348_iudma_hw *hw;
+	void __iomem *base;
+	void __iomem *chan;
+	void __iomem *sram;
+	struct bcm6348_chan_priv **ch_priv;
+	uint8_t n_channels;
+};
+
+static inline bool bcm6348_iudma_chan_is_rx(uint8_t ch)
+{
+	return !(ch & 1);
+}
+
+static void bcm6348_iudma_chan_stop(struct bcm6348_iudma_priv *priv,
+				    uint8_t ch)
+{
+	unsigned int timeout = DMA_CHAN_TOUT;
+
+	do {
+		uint32_t cfg, halt;
+
+		if (timeout > DMA_CHAN_TOUT / 2)
+			halt = DMAC_CFG_PKT_HALT_MASK;
+		else
+			halt = DMAC_CFG_BRST_HALT_MASK;
+
+		/* try to stop dma channel */
+		writel_be(halt, priv->chan + DMAC_CFG_REG(ch));
+		mb();
+
+		/* check if channel was stopped */
+		cfg = readl_be(priv->chan + DMAC_CFG_REG(ch));
+		if (!(cfg & DMAC_CFG_ENABLE_MASK))
+			break;
+
+		udelay(1);
+	} while (--timeout);
+
+	if (!timeout)
+		pr_err("unable to stop channel %u\n", ch);
+
+	/* reset dma channel */
+	setbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
+	mb();
+	clrbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
+}
+
+static int bcm6348_iudma_disable(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+
+	bcm6348_iudma_chan_stop(priv, dma->id);
+
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		writel_be(DMA_FLOWC_ALLOC_FORCE_MASK,
+			  DMA_FLOWC_ALLOC_REG(dma->id));
+
+	return 0;
+}
+
+static int bcm6348_iudma_enable(struct dma *dma)
+{
+	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	void __iomem *dma_buff = ch_priv->dma_buff;
+	uint8_t i;
+
+	/* init dma rings */
+	dma_desc = ch_priv->dma_ring;
+	for (i = 0; i < ch_priv->dma_ring_size; i++) {
+		if (bcm6348_iudma_chan_is_rx(dma->id)) {
+			dma_desc->status = DMAD_ST_OWN_MASK;
+			dma_desc->length = PKTSIZE_ALIGN;
+			dma_desc->address = virt_to_phys(dma_buff);
+			dma_buff += PKTSIZE_ALIGN;
+		} else {
+			dma_desc->status = 0;
+			dma_desc->length = 0;
+			dma_desc->address = 0;
+		}
+
+		if (i == ch_priv->dma_ring_size - 1)
+			dma_desc->status |= DMAD_ST_WRAP_MASK;
+
+		dma_desc++;
+	}
+
+	/* init to first descriptor */
+	ch_priv->desc_id = 0;
+
+	/* force cache writeback */
+	flush_dcache_range((ulong)ch_priv->dma_ring,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, ch_priv->dma_ring,
+			       ch_priv->dma_ring_size));
+
+	/* clear sram */
+	writel_be(0, priv->sram + DMAS_STATE_DATA_REG(dma->id));
+	writel_be(0, priv->sram + DMAS_DESC_LEN_STATUS_REG(dma->id));
+	writel_be(0, priv->sram + DMAS_DESC_BASE_BUFPTR_REG(dma->id));
+
+	/* set dma ring start */
+	writel_be(virt_to_phys(ch_priv->dma_ring),
+		  priv->sram + DMAS_RSTART_REG(dma->id));
+
+	/* set flow control */
+	if (bcm6348_iudma_chan_is_rx(dma->id)) {
+		u32 val;
+
+		setbits_be32(priv->base + DMA_CFG_REG,
+			     DMA_CFG_FLOWC_ENABLE(dma->id));
+
+		val = ch_priv->dma_ring_size / 3;
+		writel_be(val, priv->base + DMA_FLOWC_THR_LO_REG(dma->id));
+
+		val = (ch_priv->dma_ring_size * 2) / 3;
+		writel_be(val, priv->base + DMA_FLOWC_THR_HI_REG(dma->id));
+
+		writel_be(0, priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
+	}
+
+	/* set dma max burst */
+	writel_be(ch_priv->dma_ring_size,
+		  priv->chan + DMAC_BURST_REG(dma->id));
+
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	return 0;
+}
+
+static int bcm6348_iudma_request(struct dma *dma)
+{
+	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv;
+
+	/* check if channel is valid */
+	if (dma->id >= priv->n_channels)
+		return -ENODEV;
+
+	/* alloc channel private data */
+	priv->ch_priv[dma->id] = calloc(1, sizeof(struct bcm6348_chan_priv));
+	if (!priv->ch_priv[dma->id])
+		return -ENOMEM;
+	ch_priv = priv->ch_priv[dma->id];
+
+	/* alloc dma ring */
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		ch_priv->dma_ring_size = DMA_RX_DESC;
+	else
+		ch_priv->dma_ring_size = DMA_TX_DESC;
+
+	ch_priv->dma_ring =
+		malloc_cache_aligned(sizeof(struct bcm6348_dma_desc) *
+				     ch_priv->dma_ring_size);
+	if (!ch_priv->dma_ring)
+		return -ENOMEM;
+
+	if (bcm6348_iudma_chan_is_rx(dma->id)) {
+		ch_priv->dma_buff =
+			malloc_cache_aligned(PKTSIZE_ALIGN *
+					     ch_priv->dma_ring_size);
+		if (!ch_priv->dma_buff)
+			return -ENOMEM;
+	} else {
+		ch_priv->dma_buff = NULL;
+	}
+
+	return 0;
+}
+
+static int bcm6348_iudma_receive(struct dma *dma, void **dst)
+{
+	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	const struct bcm6348_iudma_hw *hw = priv->hw;
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	void __iomem *dma_buff;
+	int ret;
+
+	/* get dma ring descriptor address */
+	dma_desc = ch_priv->dma_ring;
+	dma_desc += ch_priv->desc_id;
+
+	/* invalidate cache data */
+	invalidate_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* check dma own */
+	if (dma_desc->status & DMAD_ST_OWN_MASK)
+		return -EAGAIN;
+
+	/* check pkt */
+	if (!(dma_desc->status & DMAD_ST_EOP_MASK) ||
+	    !(dma_desc->status & DMAD_ST_SOP_MASK) ||
+	    (dma_desc->status & hw->err_mask)) {
+		pr_err("invalid pkt received (ch=%ld) (st=%04x)\n",
+		       dma->id, dma_desc->status);
+		ret = -EAGAIN;
+	} else {
+		uint16_t length;
+
+		/* get dma buff descriptor address */
+		dma_buff = phys_to_virt(dma_desc->address);
+
+		/* invalidate cache data */
+		invalidate_dcache_range((ulong)dma_buff,
+					(ulong)(dma_buff + PKTSIZE_ALIGN));
+
+		/* remove crc */
+		length = dma_desc->length - 4;
+
+		/* copy data */
+		memcpy(*dst, dma_buff, length);
+
+		ret = length;
+	}
+
+	/* reinit dma descriptor */
+	dma_desc->length = PKTSIZE_ALIGN;
+	dma_desc->status = (dma_desc->status & DMAD_ST_WRAP_MASK) |
+			   DMAD_ST_OWN_MASK;
+
+	/* flush cache */
+	flush_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* enable dma */
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	/* increment dma descriptor */
+	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->dma_ring_size;
+
+	return ret;
+}
+
+static int bcm6348_iudma_send(struct dma *dma, void *src, size_t len)
+{
+	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	uint16_t val;
+
+	/* get dma ring descriptor address */
+	dma_desc = ch_priv->dma_ring;
+	dma_desc += ch_priv->desc_id;
+
+	dma_desc->address = virt_to_phys(src);
+
+	/* config dma descriptor */
+	val = (DMAD_ST_OWN_MASK |
+	       DMAD_ST_EOP_MASK |
+	       DMAD_ST_CRC_MASK |
+	       DMAD_ST_SOP_MASK);
+	if (ch_priv->desc_id == ch_priv->dma_ring_size - 1)
+		val |= DMAD_ST_WRAP_MASK;
+
+	dma_desc->length = len;
+	dma_desc->status = val;
+
+	/* flush cache */
+	flush_dcache_range((ulong)src, (ulong)src + PKTSIZE_ALIGN);
+
+	/* flush cache */
+	flush_dcache_range((ulong)dma_desc,
+		ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+	/* enable dma */
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	/* poll dma status */
+	do {
+		/* invalidate cache */
+		invalidate_dcache_range((ulong)dma_desc,
+			ALIGN_END_ADDR(struct bcm6348_dma_desc, dma_desc, 1));
+
+		if (!(dma_desc->status & DMAD_ST_OWN_MASK))
+			break;
+	} while(1);
+
+	/* increment dma descriptor */
+	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->dma_ring_size;
+
+	return 0;
+}
+
+static const struct dma_ops bcm6348_iudma_ops = {
+	.disable = bcm6348_iudma_disable,
+	.enable = bcm6348_iudma_enable,
+	.request = bcm6348_iudma_request,
+	.receive = bcm6348_iudma_receive,
+	.send = bcm6348_iudma_send,
+};
+
+static const struct bcm6348_iudma_hw bcm6348_hw = {
+	.err_mask = (DMAD6348_ST_OV_ERR_MASK |
+		     DMAD6348_ST_CRC_ERR_MASK |
+		     DMAD6348_ST_RX_ERR_MASK |
+		     DMAD6348_ST_OS_ERR_MASK |
+		     DMAD6348_ST_UN_ERR_MASK),
+};
+
+static const struct bcm6348_iudma_hw bcm6368_hw = {
+	.err_mask = 0,
+};
+
+static const struct udevice_id bcm6348_iudma_ids[] = {
+	{
+		.compatible = "brcm,bcm6348-iudma",
+		.data = (ulong)&bcm6348_hw,
+	}, {
+		.compatible = "brcm,bcm6368-iudma",
+		.data = (ulong)&bcm6368_hw,
+	}, { /* sentinel */ }
+};
+
+static int bcm6348_iudma_probe(struct udevice *dev)
+{
+	struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dev);
+	const struct bcm6348_iudma_hw *hw =
+		(const struct bcm6348_iudma_hw *)dev_get_driver_data(dev);
+	fdt_addr_t addr;
+	uint8_t ch;
+	int i;
+
+	uc_priv->supported = (DMA_SUPPORTS_DEV_TO_MEM |
+			      DMA_SUPPORTS_MEM_TO_DEV);
+	priv->hw = hw;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+		if (clk_enable(&clk))
+			pr_err("failed to enable clock %d\n", i);
+		clk_free(&clk);
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+		if (reset_deassert(&reset))
+			pr_err("failed to deassert reset %d\n", i);
+		reset_free(&reset);
+	}
+
+	/* dma global base address */
+	addr = devfdt_get_addr_name(dev, "dma");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->base = ioremap(addr, 0);
+
+	/* dma channels base address */
+	addr = devfdt_get_addr_name(dev, "dma-channels");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->chan = ioremap(addr, 0);
+
+	/* dma sram base address */
+	addr = devfdt_get_addr_name(dev, "dma-sram");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+	priv->sram = ioremap(addr, 0);
+
+	/* disable dma controller */
+	clrbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
+
+	/* get number of channels */
+	priv->n_channels = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+					   "dma-channels", 8);
+	if (priv->n_channels > DMA_CHAN_MAX)
+		return -EINVAL;
+
+	/* alloc channel private data pointers */
+	priv->ch_priv = calloc(priv->n_channels,
+			       sizeof(struct bcm6348_chan_priv*));
+	if (!priv->ch_priv)
+		return -ENOMEM;
+
+	/* stop dma channels */
+	for (ch = 0; ch < priv->n_channels; ch++)
+		bcm6348_iudma_chan_stop(priv, ch);
+
+	/* enable dma controller */
+	setbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_iudma) = {
+	.name = "bcm6348_iudma",
+	.id = UCLASS_DMA,
+	.of_match = bcm6348_iudma_ids,
+	.ops = &bcm6348_iudma_ops,
+	.priv_auto_alloc_size = sizeof(struct bcm6348_iudma_priv),
+	.probe = bcm6348_iudma_probe,
+};
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 04/15] bmips: bcm6338: add bcm6348-iudma support
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (2 preceding siblings ...)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 05/15] bmips: bcm6348: " Álvaro Fernández Rojas
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: no changes
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6338.dtsi       | 14 ++++++++++++++
 include/dt-bindings/dma/bcm6338-dma.h | 15 +++++++++++++++
 2 files changed, 29 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6338-dma.h

diff --git a/arch/mips/dts/brcm,bcm6338.dtsi b/arch/mips/dts/brcm,bcm6338.dtsi
index 0cab44cb8d..4125f71d9f 100644
--- a/arch/mips/dts/brcm,bcm6338.dtsi
+++ b/arch/mips/dts/brcm,bcm6338.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6338-clock.h>
+#include <dt-bindings/dma/bcm6338-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6338-reset.h>
 #include "skeleton.dtsi"
@@ -131,5 +132,18 @@
 			reg = <0xfffe3100 0x38>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller at fffe2400 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe2400 0x1c>,
+			      <0xfffe2500 0x60>,
+			      <0xfffe2600 0x60>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <6>;
+			resets = <&periph_rst BCM6338_RST_DMAMEM>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6338-dma.h b/include/dt-bindings/dma/bcm6338-dma.h
new file mode 100644
index 0000000000..5dd66239b4
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6338-dma.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6338_H
+#define __DT_BINDINGS_DMA_BCM6338_H
+
+#define BCM6338_DMA_ENET_RX	0
+#define BCM6338_DMA_ENET_TX	1
+
+#endif /* __DT_BINDINGS_DMA_BCM6338_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 05/15] bmips: bcm6348: add bcm6348-iudma support
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (3 preceding siblings ...)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 04/15] bmips: bcm6338: " Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 06/15] bmips: bcm6358: " Álvaro Fernández Rojas
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: no changes
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6348.dtsi       | 16 ++++++++++++++++
 include/dt-bindings/dma/bcm6348-dma.h | 17 +++++++++++++++++
 2 files changed, 33 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6348-dma.h

diff --git a/arch/mips/dts/brcm,bcm6348.dtsi b/arch/mips/dts/brcm,bcm6348.dtsi
index 92fb91afc1..d774c59665 100644
--- a/arch/mips/dts/brcm,bcm6348.dtsi
+++ b/arch/mips/dts/brcm,bcm6348.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6348-clock.h>
+#include <dt-bindings/dma/bcm6348-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6348-reset.h>
 #include "skeleton.dtsi"
@@ -160,5 +161,20 @@
 			reg = <0xfffe2300 0x38>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller at fffe7000 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe7000 0x1c>,
+			      <0xfffe7100 0x40>,
+			      <0xfffe7200 0x40>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <4>;
+			clocks = <&periph_clk BCM6348_CLK_ENET>;
+			resets = <&periph_rst BCM6348_RST_ENET>,
+				 <&periph_rst BCM6348_RST_DMAMEM>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6348-dma.h b/include/dt-bindings/dma/bcm6348-dma.h
new file mode 100644
index 0000000000..a1d3a6456d
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6348-dma.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6348_H
+#define __DT_BINDINGS_DMA_BCM6348_H
+
+#define BCM6348_DMA_ENET0_RX	0
+#define BCM6348_DMA_ENET0_TX	1
+#define BCM6348_DMA_ENET1_RX	2
+#define BCM6348_DMA_ENET1_TX	3
+
+#endif /* __DT_BINDINGS_DMA_BCM6348_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 06/15] bmips: bcm6358: add bcm6348-iudma support
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (4 preceding siblings ...)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 05/15] bmips: bcm6348: " Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 07/15] phy: add support for internal phys Álvaro Fernández Rojas
                     ` (8 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: no changes
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6358.dtsi       | 18 ++++++++++++++++++
 include/dt-bindings/dma/bcm6358-dma.h | 17 +++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 include/dt-bindings/dma/bcm6358-dma.h

diff --git a/arch/mips/dts/brcm,bcm6358.dtsi b/arch/mips/dts/brcm,bcm6358.dtsi
index b63b53baee..1468e4f63a 100644
--- a/arch/mips/dts/brcm,bcm6358.dtsi
+++ b/arch/mips/dts/brcm,bcm6358.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/clock/bcm6358-clock.h>
+#include <dt-bindings/dma/bcm6358-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6358-reset.h>
 #include "skeleton.dtsi"
@@ -191,5 +192,22 @@
 
 			status = "disabled";
 		};
+
+		iudma: dma-controller at fffe5000 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe5000 0x24>,
+			      <0xfffe5100 0x80>,
+			      <0xfffe5200 0x80>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <8>;
+			clocks = <&periph_clk BCM6358_CLK_EMUSB>,
+				 <&periph_clk BCM6358_CLK_USBSU>,
+				 <&periph_clk BCM6358_CLK_EPHY>;
+			resets = <&periph_rst BCM6358_RST_ENET>,
+				 <&periph_rst BCM6358_RST_EPHY>;
+		};
 	};
 };
diff --git a/include/dt-bindings/dma/bcm6358-dma.h b/include/dt-bindings/dma/bcm6358-dma.h
new file mode 100644
index 0000000000..3b1fcf8540
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6358-dma.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6358_H
+#define __DT_BINDINGS_DMA_BCM6358_H
+
+#define BCM6358_DMA_ENET0_RX	0
+#define BCM6358_DMA_ENET0_TX	1
+#define BCM6358_DMA_ENET1_RX	2
+#define BCM6358_DMA_ENET1_TX	3
+
+#endif /* __DT_BINDINGS_DMA_BCM6358_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 07/15] phy: add support for internal phys
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (5 preceding siblings ...)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 06/15] bmips: bcm6358: " Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-07 20:28     ` Joe Hershberger
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
                     ` (7 subsequent siblings)
  14 siblings, 1 reply; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: no changes
 v4: no changes
 v3: no changes
 v2: no changes

 include/phy.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/phy.h b/include/phy.h
index 0543ec10c2..8f3e53db01 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -50,6 +50,7 @@
 
 
 typedef enum {
+	PHY_INTERFACE_MODE_INTERNAL,
 	PHY_INTERFACE_MODE_MII,
 	PHY_INTERFACE_MODE_GMII,
 	PHY_INTERFACE_MODE_SGMII,
@@ -72,6 +73,7 @@ typedef enum {
 } phy_interface_t;
 
 static const char *phy_interface_strings[] = {
+	[PHY_INTERFACE_MODE_INTERNAL]		= "internal",
 	[PHY_INTERFACE_MODE_MII]		= "mii",
 	[PHY_INTERFACE_MODE_GMII]		= "gmii",
 	[PHY_INTERFACE_MODE_SGMII]		= "sgmii",
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 08/15] net: add support for bcm6348-enet
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (6 preceding siblings ...)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 07/15] phy: add support for internal phys Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-07 21:46     ` Joe Hershberger
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 09/15] bmips: bcm6338: " Álvaro Fernández Rojas
                     ` (6 subsequent siblings)
  14 siblings, 1 reply; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: Receive as much packets as possible from bcm6348-eth and cache them in
 net_rx_packets. This is needed in order to fix flow control issues.
 v4: Fix issues reported by Grygorii Strashko and other fixes:
  - Copy received dma buffer to net_rx_packets in order to avoid possible
  dma overwrites.
  - Reset dma rx channel when sending a new packet to prevent flow control
  issues.
  - Fix packet casting on bcm6348_eth_recv/send.
 v3: no changes
 v2: select DMA_CHANNELS.

 drivers/net/Kconfig            |  10 +
 drivers/net/Makefile           |   1 +
 drivers/net/bcm6348-eth.c      | 575 +++++++++++++++++++++++++++++++++++++++++
 include/configs/bmips_common.h |   5 +-
 4 files changed, 590 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/bcm6348-eth.c

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index de1947ccc1..e532332d78 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -71,6 +71,16 @@ config BCM_SF2_ETH_GMAC
 	  by the BCM_SF2_ETH driver.
 	  Say Y to any bcmcygnus based platforms.
 
+config BCM6348_ETH
+	bool "BCM6348 EMAC support"
+	depends on DM_ETH && ARCH_BMIPS
+	select DMA
+	select DMA_CHANNELS
+	select MII
+	select PHYLIB
+	help
+	  This driver supports the BCM6348 Ethernet MAC.
+
 config DWC_ETH_QOS
 	bool "Synopsys DWC Ethernet QOS device support"
 	depends on DM_ETH
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index ac5443c752..282adbc775 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
 obj-$(CONFIG_AG7XXX) += ag7xxx.o
 obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
+obj-$(CONFIG_BCM6348_ETH) += bcm6348-eth.o
 obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
 obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
 obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
diff --git a/drivers/net/bcm6348-eth.c b/drivers/net/bcm6348-eth.c
new file mode 100644
index 0000000000..43518f7b2d
--- /dev/null
+++ b/drivers/net/bcm6348-eth.c
@@ -0,0 +1,575 @@
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma.h>
+#include <miiphy.h>
+#include <net.h>
+#include <phy.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+
+#define ETH_RX_DESC			PKTBUFSRX
+#define ETH_MAX_MTU_SIZE		1518
+#define ETH_TIMEOUT			100
+#define ETH_TX_WATERMARK		32
+
+/* ETH Receiver Configuration register */
+#define ETH_RXCFG_REG			0x00
+#define ETH_RXCFG_ENFLOW_SHIFT		5
+#define ETH_RXCFG_ENFLOW_MASK		(1 << ETH_RXCFG_ENFLOW_SHIFT)
+
+/* ETH Receive Maximum Length register */
+#define ETH_RXMAXLEN_REG		0x04
+#define ETH_RXMAXLEN_SHIFT		0
+#define ETH_RXMAXLEN_MASK		(0x7ff << ETH_RXMAXLEN_SHIFT)
+
+/* ETH Transmit Maximum Length register */
+#define ETH_TXMAXLEN_REG		0x08
+#define ETH_TXMAXLEN_SHIFT		0
+#define ETH_TXMAXLEN_MASK		(0x7ff << ETH_TXMAXLEN_SHIFT)
+
+/* MII Status/Control register */
+#define MII_SC_REG			0x10
+#define MII_SC_MDCFREQDIV_SHIFT		0
+#define MII_SC_MDCFREQDIV_MASK		(0x7f << MII_SC_MDCFREQDIV_SHIFT)
+#define MII_SC_PREAMBLE_EN_SHIFT	7
+#define MII_SC_PREAMBLE_EN_MASK		(1 << MII_SC_PREAMBLE_EN_SHIFT)
+
+/* MII Data register */
+#define MII_DAT_REG			0x14
+#define MII_DAT_DATA_SHIFT		0
+#define MII_DAT_DATA_MASK		(0xffff << MII_DAT_DATA_SHIFT)
+#define MII_DAT_TA_SHIFT		16
+#define MII_DAT_TA_MASK			(0x3 << MII_DAT_TA_SHIFT)
+#define MII_DAT_REG_SHIFT		18
+#define MII_DAT_REG_MASK		(0x1f << MII_DAT_REG_SHIFT)
+#define MII_DAT_PHY_SHIFT		23
+#define MII_DAT_PHY_MASK		(0x1f << MII_DAT_PHY_SHIFT)
+#define MII_DAT_OP_SHIFT		28
+#define MII_DAT_OP_WRITE		(0x5 << MII_DAT_OP_SHIFT)
+#define MII_DAT_OP_READ			(0x6 << MII_DAT_OP_SHIFT)
+
+/* ETH Interrupts Mask register */
+#define ETH_IRMASK_REG			0x18
+
+/* ETH Interrupts register */
+#define ETH_IR_REG			0x1c
+#define ETH_IR_MII_SHIFT		0
+#define ETH_IR_MII_MASK			(1 << ETH_IR_MII_SHIFT)
+
+/* ETH Control register */
+#define ETH_CTL_REG			0x2c
+#define ETH_CTL_ENABLE_SHIFT		0
+#define ETH_CTL_ENABLE_MASK		(1 << ETH_CTL_ENABLE_SHIFT)
+#define ETH_CTL_DISABLE_SHIFT		1
+#define ETH_CTL_DISABLE_MASK		(1 << ETH_CTL_DISABLE_SHIFT)
+#define ETH_CTL_RESET_SHIFT		2
+#define ETH_CTL_RESET_MASK		(1 << ETH_CTL_RESET_SHIFT)
+#define ETH_CTL_EPHY_SHIFT		3
+#define ETH_CTL_EPHY_MASK		(1 << ETH_CTL_EPHY_SHIFT)
+
+/* ETH Transmit Control register */
+#define ETH_TXCTL_REG			0x30
+#define ETH_TXCTL_FD_SHIFT		0
+#define ETH_TXCTL_FD_MASK		(1 << ETH_TXCTL_FD_SHIFT)
+
+/* ETH Transmit Watermask register */
+#define ETH_TXWMARK_REG			0x34
+#define ETH_TXWMARK_WM_SHIFT		0
+#define ETH_TXWMARK_WM_MASK		(0x3f << ETH_TXWMARK_WM_SHIFT)
+
+/* MIB Control register */
+#define MIB_CTL_REG			0x38
+#define MIB_CTL_RDCLEAR_SHIFT		0
+#define MIB_CTL_RDCLEAR_MASK		(1 << MIB_CTL_RDCLEAR_SHIFT)
+
+/* ETH Perfect Match registers */
+#define ETH_PM_CNT			4
+#define ETH_PML_REG(x)			(0x58 + (x) * 0x8)
+#define ETH_PMH_REG(x)			(0x5c + (x) * 0x8)
+#define ETH_PMH_VALID_SHIFT		16
+#define ETH_PMH_VALID_MASK		(1 << ETH_PMH_VALID_SHIFT)
+
+/* MIB Counters registers */
+#define MIB_REG_CNT			55
+#define MIB_REG(x)			(0x200 + (x) * 4)
+
+/* ETH data */
+struct bcm6348_eth_priv {
+	void __iomem *base;
+	/* RX */
+	uint8_t rx_desc;
+	uint8_t rx_pend;
+	int rx_ret[ETH_RX_DESC];
+	/* DMA */
+	struct dma rx_dma;
+	struct dma tx_dma;
+	/* PHY */
+	int phy_id;
+	struct phy_device *phy_dev;
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void bcm6348_eth_mac_disable(struct bcm6348_eth_priv *priv)
+{
+	/* disable emac */
+	clrsetbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK,
+			ETH_CTL_DISABLE_MASK);
+
+	/* wait until emac is disabled */
+	if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
+			      ETH_CTL_DISABLE_MASK, false,
+			      ETH_TIMEOUT, false))
+		pr_err("error disabling emac\n");
+}
+
+static void bcm6348_eth_mac_enable(struct bcm6348_eth_priv *priv)
+{
+	setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK);
+}
+
+static void bcm6348_eth_mac_reset(struct bcm6348_eth_priv *priv)
+{
+	/* reset emac */
+	writel_be(ETH_CTL_RESET_MASK, priv->base + ETH_CTL_REG);
+	wmb();
+
+	/* wait until emac is reset */
+	if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
+			      ETH_CTL_RESET_MASK, false,
+			      ETH_TIMEOUT, false))
+		pr_err("error resetting emac\n");
+}
+
+static int bcm6348_eth_free_pkt(struct udevice *dev, uchar *packet, int len)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* sanity check */
+	if (packet != net_rx_packets[priv->rx_pend]) {
+		pr_err("rx_pend %d: packet is not matched,\n", priv->rx_pend);
+		return -EAGAIN;
+	}
+
+	/* free pending packet */
+	priv->rx_ret[priv->rx_pend] = 0;
+	priv->rx_pend = (priv->rx_pend + 1) % ETH_RX_DESC;
+
+	return 0;
+}
+
+static int _bcm6348_eth_recv(struct bcm6348_eth_priv *priv)
+{
+	uint8_t pkt = priv->rx_desc;
+
+	/* check if packet is free */
+	if (priv->rx_ret[pkt] > 0)
+		return -EAGAIN;
+
+	/* try to receive a new packet */
+	priv->rx_ret[pkt] = dma_receive(&priv->rx_dma,
+					(void **)&net_rx_packets[pkt]);
+	if (priv->rx_ret[pkt] > 0)
+		priv->rx_desc = (priv->rx_desc + 1) % ETH_RX_DESC;
+
+	return priv->rx_ret[pkt];
+}
+
+static int bcm6348_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	uint8_t pkt_cnt = 0;
+	int ret;
+
+	/* try to receive packets */
+	while (_bcm6348_eth_recv(priv) > 0)
+		pkt_cnt++;
+
+	if (pkt_cnt)
+		debug("%s: received %u packet(s)\n", __func__, pkt_cnt);
+
+	/* return current packet */
+	ret = priv->rx_ret[priv->rx_pend];
+	if (ret > 0)
+		*packetp = net_rx_packets[priv->rx_pend];
+
+	return ret;
+}
+
+static int bcm6348_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* reset dma rx channel */
+	dma_disable(&priv->rx_dma);
+	dma_enable(&priv->rx_dma);
+
+	return dma_send(&priv->tx_dma, (void *)packet, length);
+}
+
+static int bcm6348_eth_adjust_link(struct udevice *dev,
+				   struct phy_device *phydev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* mac duplex parameters */
+	if (phydev->duplex)
+		setbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
+	else
+		clrbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
+
+	/* rx flow control (pause frame handling) */
+	if (phydev->pause)
+		setbits_be32(priv->base + ETH_RXCFG_REG,
+			     ETH_RXCFG_ENFLOW_MASK);
+	else
+		clrbits_be32(priv->base + ETH_RXCFG_REG,
+			     ETH_RXCFG_ENFLOW_MASK);
+
+	return 0;
+}
+
+static int bcm6348_eth_start(struct udevice *dev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	int ret, i;
+
+	priv->rx_desc = 0;
+	priv->rx_pend = 0;
+	for (i = 0; i < ETH_RX_DESC; i++)
+		priv->rx_ret[i] = 0;
+
+	/* enable dma rx channel */
+	dma_enable(&priv->rx_dma);
+
+	/* enable dma tx channel */
+	dma_enable(&priv->tx_dma);
+
+	ret = phy_startup(priv->phy_dev);
+	if (ret) {
+		pr_err("could not initialize phy\n");
+		return ret;
+	}
+
+	if (!priv->phy_dev->link) {
+		pr_err("no phy link\n");
+		return -EIO;
+	}
+
+	bcm6348_eth_adjust_link(dev, priv->phy_dev);
+
+	/* zero mib counters */
+	for (i = 0; i < MIB_REG_CNT; i++)
+		writel_be(0, MIB_REG(i));
+
+	/* enable rx flow control */
+	setbits_be32(priv->base + ETH_RXCFG_REG, ETH_RXCFG_ENFLOW_MASK);
+
+	/* set max rx/tx length */
+	writel_be((ETH_MAX_MTU_SIZE << ETH_RXMAXLEN_SHIFT) &
+		  ETH_RXMAXLEN_MASK, priv->base + ETH_RXMAXLEN_REG);
+	writel_be((ETH_MAX_MTU_SIZE << ETH_TXMAXLEN_SHIFT) &
+		   ETH_TXMAXLEN_MASK, priv->base + ETH_TXMAXLEN_REG);
+
+	/* set correct transmit fifo watermark */
+	writel_be((ETH_TX_WATERMARK << ETH_TXWMARK_WM_SHIFT) &
+		  ETH_TXWMARK_WM_MASK, priv->base + ETH_TXWMARK_REG);
+
+	/* enable emac */
+	bcm6348_eth_mac_enable(priv);
+
+	/* clear interrupts */
+	writel_be(0, priv->base + ETH_IRMASK_REG);
+
+	return 0;
+}
+
+static void bcm6348_eth_stop(struct udevice *dev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* disable dma rx channel */
+	dma_disable(&priv->rx_dma);
+
+	/* disable dma tx channel */
+	dma_disable(&priv->tx_dma);
+
+	/* disable emac */
+	bcm6348_eth_mac_disable(priv);
+}
+
+static int bcm6348_eth_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	bool running = false;
+
+	/* check if emac is running */
+	if (readl_be(priv->base + ETH_CTL_REG) & ETH_CTL_ENABLE_MASK)
+		running = true;
+
+	/* disable emac */
+	if (running)
+		bcm6348_eth_mac_disable(priv);
+
+	/* set mac address */
+	writel_be((pdata->enetaddr[2] << 24) | (pdata->enetaddr[3]) << 16 |
+		  (pdata->enetaddr[4]) << 8 | (pdata->enetaddr[5]),
+		  priv->base + ETH_PML_REG(0));
+	writel_be((pdata->enetaddr[1]) | (pdata->enetaddr[0] << 8) |
+		  ETH_PMH_VALID_MASK, priv->base + ETH_PMH_REG(0));
+
+	/* enable emac */
+	if (running)
+		bcm6348_eth_mac_enable(priv);
+
+	return 0;
+}
+
+static const struct eth_ops bcm6348_eth_ops = {
+	.free_pkt = bcm6348_eth_free_pkt,
+	.recv = bcm6348_eth_recv,
+	.send = bcm6348_eth_send,
+	.start = bcm6348_eth_start,
+	.stop = bcm6348_eth_stop,
+	.write_hwaddr = bcm6348_eth_write_hwaddr,
+};
+
+static const struct udevice_id bcm6348_eth_ids[] = {
+	{ .compatible = "brcm,bcm6348-enet", },
+	{ /* sentinel */ }
+};
+
+static int bcm6348_mdio_op(void __iomem *base, uint32_t data)
+{
+	/* make sure mii interrupt status is cleared */
+	writel_be(ETH_IR_MII_MASK, base + ETH_IR_REG);
+
+	/* issue mii op */
+	writel_be(data, base + MII_DAT_REG);
+
+	/* wait until emac is disabled */
+	return wait_for_bit_be32(base + ETH_IR_REG,
+				 ETH_IR_MII_MASK, true,
+				 ETH_TIMEOUT, false);
+}
+
+static int bcm6348_mdio_read(struct mii_dev *bus, int addr, int devaddr,
+			     int reg)
+{
+	void __iomem *base = bus->priv;
+	uint32_t val;
+
+	val = MII_DAT_OP_READ;
+	val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
+	val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
+	val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
+
+	if (bcm6348_mdio_op(base, val)) {
+		pr_err("%s: timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	val = readl_be(base + MII_DAT_REG) & MII_DAT_DATA_MASK;
+	val >>= MII_DAT_DATA_SHIFT;
+
+	return val;
+}
+
+static int bcm6348_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
+			      int reg, u16 value)
+{
+	void __iomem *base = bus->priv;
+	uint32_t val;
+
+	val = MII_DAT_OP_WRITE;
+	val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
+	val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
+	val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
+	val |= (value << MII_DAT_DATA_SHIFT) & MII_DAT_DATA_MASK;
+
+	if (bcm6348_mdio_op(base, val)) {
+		pr_err("%s: timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int bcm6348_mdio_init(const char *name, void __iomem *base)
+{
+	struct mii_dev *bus;
+
+	bus = mdio_alloc();
+	if (!bus) {
+		pr_err("%s: failed to allocate MDIO bus\n", __func__);
+		return -ENOMEM;
+	}
+
+	bus->read = bcm6348_mdio_read;
+	bus->write = bcm6348_mdio_write;
+	bus->priv = base;
+	snprintf(bus->name, sizeof(bus->name), "%s", name);
+
+	return mdio_register(bus);
+}
+
+static int bcm6348_phy_init(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	struct mii_dev *bus;
+
+	/* get mii bus */
+	bus = miiphy_get_dev_by_name(dev->name);
+
+	/* phy connect */
+	priv->phy_dev = phy_connect(bus, priv->phy_id, dev,
+				    pdata->phy_interface);
+	if (!priv->phy_dev) {
+		pr_err("%s: no phy device\n", __func__);
+		return -ENODEV;
+	}
+
+	priv->phy_dev->supported = (SUPPORTED_10baseT_Half |
+				    SUPPORTED_10baseT_Full |
+				    SUPPORTED_100baseT_Half |
+				    SUPPORTED_100baseT_Full |
+				    SUPPORTED_Autoneg |
+				    SUPPORTED_Pause |
+				    SUPPORTED_MII);
+	priv->phy_dev->advertising = priv->phy_dev->supported;
+
+	/* phy config */
+	phy_config(priv->phy_dev);
+
+	return 0;
+}
+
+static int bcm6348_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	void *blob = (void *)gd->fdt_blob;
+	int node = dev_of_offset(dev);
+	const char *phy_mode;
+	fdt_addr_t addr;
+	int phy_node, ret, i;
+
+	/* get base address */
+	addr = devfdt_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	/* get phy mode */
+	pdata->phy_interface = PHY_INTERFACE_MODE_NONE;
+	phy_mode = fdt_getprop(blob, node, "phy-mode", NULL);
+	if (phy_mode)
+		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_NONE)
+		return -ENODEV;
+
+	/* get phy */
+	phy_node = fdtdec_lookup_phandle(blob, node, "phy");
+	if (phy_node >= 0)
+		priv->phy_id = fdtdec_get_int(blob, phy_node, "reg", -1);
+	else
+		return -EINVAL;
+
+	/* get dma channels */
+	ret = dma_get_by_name(dev, "tx", &priv->tx_dma);
+	if (ret)
+		return -EINVAL;
+
+	ret = dma_get_by_name(dev, "rx", &priv->rx_dma);
+	if (ret)
+		return -EINVAL;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+		if (clk_enable(&clk))
+			pr_err("failed to enable clock %d\n", i);
+		clk_free(&clk);
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+		if (reset_deassert(&reset))
+			pr_err("failed to deassert reset %d\n", i);
+		reset_free(&reset);
+	}
+
+	/* get base addr */
+	priv->base = ioremap(addr, 0);
+	pdata->iobase = (phys_addr_t) priv->base;
+
+	/* disable emac */
+	bcm6348_eth_mac_disable(priv);
+
+	/* reset emac */
+	bcm6348_eth_mac_reset(priv);
+
+	/* select correct mii interface */
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_INTERNAL)
+		clrbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
+	else
+		setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
+
+	/* turn on mdc clock */
+	writel_be((0x1f << MII_SC_MDCFREQDIV_SHIFT) |
+		  MII_SC_PREAMBLE_EN_MASK, priv->base + MII_SC_REG);
+
+	/* set mib counters to not clear when read */
+	clrbits_be32(priv->base + MIB_CTL_REG, MIB_CTL_RDCLEAR_MASK);
+
+	/* initialize perfect match registers */
+	for (i = 0; i < ETH_PM_CNT; i++) {
+		writel_be(0, priv->base + ETH_PML_REG(i));
+		writel_be(0, priv->base + ETH_PMH_REG(i));
+	}
+
+	/* init mii bus */
+	ret = bcm6348_mdio_init(dev->name, priv->base);
+	if (ret)
+		return ret;
+
+	/* init phy */
+	ret = bcm6348_phy_init(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_eth) = {
+	.name = "bcm6348_eth",
+	.id = UCLASS_ETH,
+	.of_match = bcm6348_eth_ids,
+	.ops = &bcm6348_eth_ops,
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.priv_auto_alloc_size = sizeof(struct bcm6348_eth_priv),
+	.probe = bcm6348_eth_probe,
+};
diff --git a/include/configs/bmips_common.h b/include/configs/bmips_common.h
index 38bf7a272b..eb66512f67 100644
--- a/include/configs/bmips_common.h
+++ b/include/configs/bmips_common.h
@@ -7,6 +7,9 @@
 #ifndef __CONFIG_BMIPS_COMMON_H
 #define __CONFIG_BMIPS_COMMON_H
 
+/* ETH */
+#define CONFIG_PHY_RESET_DELAY		20
+
 /* UART */
 #define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200, \
 					  230400, 500000, 1500000 }
@@ -17,7 +20,7 @@
 
 /* Memory usage */
 #define CONFIG_SYS_MAXARGS		24
-#define CONFIG_SYS_MALLOC_LEN		(1024 * 1024)
+#define CONFIG_SYS_MALLOC_LEN		(2 * 1024 * 1024)
 #define CONFIG_SYS_BOOTPARAMS_LEN	(128 * 1024)
 #define CONFIG_SYS_CBSIZE		512
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 09/15] bmips: bcm6338: add support for bcm6348-enet
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (7 preceding siblings ...)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 10/15] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: no changes
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6338.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6338.dtsi b/arch/mips/dts/brcm,bcm6338.dtsi
index 4125f71d9f..621278c9d1 100644
--- a/arch/mips/dts/brcm,bcm6338.dtsi
+++ b/arch/mips/dts/brcm,bcm6338.dtsi
@@ -145,5 +145,20 @@
 			dma-channels = <6>;
 			resets = <&periph_rst BCM6338_RST_DMAMEM>;
 		};
+
+		enet: ethernet at fffe2800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe2800 0x2dc>;
+			clocks = <&periph_clk BCM6338_CLK_ENET>;
+			resets = <&periph_rst BCM6338_RST_ENET>;
+			dmas = <&iudma BCM6338_DMA_ENET_RX>,
+			       <&iudma BCM6338_DMA_ENET_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
 	};
 };
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 10/15] bmips: enable f@st1704 enet support
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (8 preceding siblings ...)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 09/15] bmips: bcm6338: " Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 11/15] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: no changes
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/sagem,f at st1704.dts     | 12 ++++++++++++
 configs/sagem_f at st1704_ram_defconfig |  9 ++++++++-
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/sagem,f at st1704.dts b/arch/mips/dts/sagem,f at st1704.dts
index dd0e5b8b7c..99d031f10a 100644
--- a/arch/mips/dts/sagem,f at st1704.dts
+++ b/arch/mips/dts/sagem,f at st1704.dts
@@ -40,6 +40,18 @@
 	};
 };
 
+&enet {
+	status = "okay";
+	phy = <&enetphy>;
+	phy-mode = "mii";
+
+	enetphy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio {
 	status = "okay";
 };
diff --git a/configs/sagem_f at st1704_ram_defconfig b/configs/sagem_f at st1704_ram_defconfig
index 0adcd46d51..1a640781b7 100644
--- a/configs/sagem_f at st1704_ram_defconfig
+++ b/configs/sagem_f at st1704_ram_defconfig
@@ -28,11 +28,15 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_SF=y
 CONFIG_CMD_SPI=y
-# CONFIG_CMD_NET is not set
+CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -41,6 +45,9 @@ CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_DM_RESET=y
 CONFIG_RESET_BCM6345=y
 # CONFIG_SPL_SERIAL_PRESENT is not set
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 11/15] bmips: bcm6348: add support for bcm6348-enet
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (9 preceding siblings ...)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 10/15] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 12/15] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: no changes
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6348.dtsi | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6348.dtsi b/arch/mips/dts/brcm,bcm6348.dtsi
index d774c59665..e540865019 100644
--- a/arch/mips/dts/brcm,bcm6348.dtsi
+++ b/arch/mips/dts/brcm,bcm6348.dtsi
@@ -162,6 +162,32 @@
 			u-boot,dm-pre-reloc;
 		};
 
+		enet0: ethernet at fffe6000 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe6000 0x2dc>;
+			dmas = <&iudma BCM6348_DMA_ENET0_RX>,
+			       <&iudma BCM6348_DMA_ENET0_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		enet1: ethernet at fffe6800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe6800 0x2dc>;
+			dmas = <&iudma BCM6348_DMA_ENET1_RX>,
+			       <&iudma BCM6348_DMA_ENET1_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
 		iudma: dma-controller at fffe7000 {
 			compatible = "brcm,bcm6348-iudma";
 			reg = <0xfffe7000 0x1c>,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 12/15] bmips: enable ct-5361 enet support
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (10 preceding siblings ...)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 11/15] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 13/15] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: no changes
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/comtrend,ct-5361.dts    | 12 ++++++++++++
 configs/comtrend_ct5361_ram_defconfig |  8 +++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/comtrend,ct-5361.dts b/arch/mips/dts/comtrend,ct-5361.dts
index 74dc09046c..a78aa877fc 100644
--- a/arch/mips/dts/comtrend,ct-5361.dts
+++ b/arch/mips/dts/comtrend,ct-5361.dts
@@ -35,6 +35,18 @@
 	};
 };
 
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/comtrend_ct5361_ram_defconfig b/configs/comtrend_ct5361_ram_defconfig
index 8b842606f5..0737772dd2 100644
--- a/configs/comtrend_ct5361_ram_defconfig
+++ b/configs/comtrend_ct5361_ram_defconfig
@@ -26,11 +26,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -38,6 +41,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6348_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 13/15] bmips: bcm6358: add support for bcm6348-enet
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (11 preceding siblings ...)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 12/15] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 14/15] bmips: enable hg556a enet support Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 15/15] bmips: enable nb4-ser " Álvaro Fernández Rojas
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: no changes
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/brcm,bcm6358.dtsi | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/mips/dts/brcm,bcm6358.dtsi b/arch/mips/dts/brcm,bcm6358.dtsi
index 1468e4f63a..04329864c2 100644
--- a/arch/mips/dts/brcm,bcm6358.dtsi
+++ b/arch/mips/dts/brcm,bcm6358.dtsi
@@ -193,6 +193,34 @@
 			status = "disabled";
 		};
 
+		enet0: ethernet at fffe4000 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe4000 0x2dc>;
+			clocks = <&periph_clk BCM6358_CLK_ENET0>;
+			dmas = <&iudma BCM6358_DMA_ENET0_RX>,
+			       <&iudma BCM6358_DMA_ENET0_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		enet1: ethernet at fffe4800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe4800 0x2dc>;
+			clocks = <&periph_clk BCM6358_CLK_ENET1>;
+			dmas = <&iudma BCM6358_DMA_ENET1_RX>,
+			       <&iudma BCM6358_DMA_ENET1_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
 		iudma: dma-controller at fffe5000 {
 			compatible = "brcm,bcm6348-iudma";
 			reg = <0xfffe5000 0x24>,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 14/15] bmips: enable hg556a enet support
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (12 preceding siblings ...)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 13/15] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 15/15] bmips: enable nb4-ser " Álvaro Fernández Rojas
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: no changes
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/huawei,hg556a.dts     | 12 ++++++++++++
 configs/huawei_hg556a_ram_defconfig |  8 +++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/huawei,hg556a.dts b/arch/mips/dts/huawei,hg556a.dts
index a1e9c15ab9..2f99e0905c 100644
--- a/arch/mips/dts/huawei,hg556a.dts
+++ b/arch/mips/dts/huawei,hg556a.dts
@@ -94,6 +94,18 @@
 	status = "okay";
 };
 
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/huawei_hg556a_ram_defconfig b/configs/huawei_hg556a_ram_defconfig
index 7f7f34ed61..c7c7c6554f 100644
--- a/configs/huawei_hg556a_ram_defconfig
+++ b/configs/huawei_hg556a_ram_defconfig
@@ -26,11 +26,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -38,6 +41,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6358_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 15/15] bmips: enable nb4-ser enet support
  2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
                     ` (13 preceding siblings ...)
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 14/15] bmips: enable hg556a enet support Álvaro Fernández Rojas
@ 2018-03-05 20:05   ` Álvaro Fernández Rojas
  14 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:05 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
 v5: no changes
 v4: no changes
 v3: no changes
 v2: no changes

 arch/mips/dts/sfr,nb4-ser.dts     | 24 ++++++++++++++++++++++++
 configs/sfr_nb4-ser_ram_defconfig |  8 +++++++-
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/arch/mips/dts/sfr,nb4-ser.dts b/arch/mips/dts/sfr,nb4-ser.dts
index 473372faa1..73db45f9ea 100644
--- a/arch/mips/dts/sfr,nb4-ser.dts
+++ b/arch/mips/dts/sfr,nb4-ser.dts
@@ -54,6 +54,30 @@
 	status = "okay";
 };
 
+&enet0 {
+	status = "okay";
+	phy = <&enet0phy>;
+	phy-mode = "internal";
+
+	enet0phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/configs/sfr_nb4-ser_ram_defconfig b/configs/sfr_nb4-ser_ram_defconfig
index fc323d879d..07b49a1a77 100644
--- a/configs/sfr_nb4-ser_ram_defconfig
+++ b/configs/sfr_nb4-ser_ram_defconfig
@@ -27,11 +27,14 @@ CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -40,6 +43,9 @@ CONFIG_LED_GPIO=y
 CONFIG_MTD=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_CFI_FLASH=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6358_USBH_PHY=y
 CONFIG_DM_RESET=y
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 106+ messages in thread

* [U-Boot] [RFC v3 01/15] dma: move dma_ops to dma-uclass.h
  2018-03-05 19:35       ` Grygorii Strashko
@ 2018-03-05 20:06         ` Álvaro Fernández Rojas
  0 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-05 20:06 UTC (permalink / raw)
  To: u-boot

Hi Grygorii,

Thanks for reporting that, it should be fixed on v5.

Regards,

Álvaro.


El 05/03/2018 a las 20:35, Grygorii Strashko escribió:
>
> On 02/22/2018 10:18 AM, Simon Glass wrote:
>> On 21 February 2018 at 09:10, Álvaro Fernández Rojas <noltari@gmail.com> wrote:
>>> Move dma_ops to a separate header file, following other uclass implementations.
>>> While doing so, this patch also improves dma_ops documentation.
>>>
>>> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
>>> ---
>>>    v3: Introduce changes reported by Simon Glass:
>>>     - Improve dma-uclass.h documentation.
>>>     - Switch to live tree API.
>>>
>>>    drivers/dma/dma-uclass.c |  3 ++-
>>>    include/dma-uclass.h     | 39 +++++++++++++++++++++++++++++++++++++++
>>>    include/dma.h            | 22 ----------------------
>>>    3 files changed, 41 insertions(+), 23 deletions(-)
>>>    create mode 100644 include/dma-uclass.h
>> Reviewed-by: Simon Glass <sjg@chromium.org>
> this patch will break build of existing DMA drivers, as
> the do not have #include <dma-uclass.h>.
>
> drivers/dma/ti-edma3.c:563:21: error: variable 'ti_edma3_ops' has initializer but incomplete type
>   static const struct dma_ops ti_edma3_ops = {
>                       ^~~~~~~
> drivers/dma/ti-edma3.c:564:2: error: unknown field 'transfer' specified in initializer
>    .transfer = ti_edma3_transfer,
>    ^
> drivers/dma/ti-edma3.c:564:14: warning: excess elements in struct initializer
>    .transfer = ti_edma3_transfer,
>                ^~~~~~~~~~~~~~~~~
> drivers/dma/ti-edma3.c:564:14: note: (near initialization for 'ti_edma3_ops')
> drivers/dma/ti-edma3.c:563:29: error: storage size of 'ti_edma3_ops' isn't known
>   static const struct dma_ops ti_edma3_ops = {
>                               ^~~~~~~~~~~~
> make[1]: *** [drivers/dma/ti-edma3.o] Error 1
>
>

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 01/15] dma: move dma_ops to dma-uclass.h
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
@ 2018-03-06 15:10     ` Grygorii Strashko
  0 siblings, 0 replies; 106+ messages in thread
From: Grygorii Strashko @ 2018-03-06 15:10 UTC (permalink / raw)
  To: u-boot



On 03/05/2018 02:05 PM, Álvaro Fernández Rojas wrote:
> Move dma_ops to a separate header file, following other uclass implementations.
> While doing so, this patch also improves dma_ops documentation.
> 
> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
> Reviewed-by: Simon Glass <sjg@chromium.org>
> ---
>   v5: fix build of ti-edma3 (reported by Grygorii Strashko) and 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/dma-uclass.c |  2 +-
>   drivers/dma/ti-edma3.c   |  2 +-
>   include/dma-uclass.h     | 39 +++++++++++++++++++++++++++++++++++++++
>   include/dma.h            | 22 ----------------------
>   4 files changed, 41 insertions(+), 24 deletions(-)
>   create mode 100644 include/dma-uclass.h

Reviewed-by: Grygorii Strashko <grygorii.strashko@ti.com>

-- 
regards,
-grygorii

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 07/15] phy: add support for internal phys
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 07/15] phy: add support for internal phys Álvaro Fernández Rojas
@ 2018-03-07 20:28     ` Joe Hershberger
  2018-03-08 19:38       ` Álvaro Fernández Rojas
  0 siblings, 1 reply; 106+ messages in thread
From: Joe Hershberger @ 2018-03-07 20:28 UTC (permalink / raw)
  To: u-boot

On Mon, Mar 5, 2018 at 2:05 PM, Álvaro Fernández Rojas
<noltari@gmail.com> wrote:
> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
> ---
>  v5: no changes
>  v4: no changes
>  v3: no changes
>  v2: no changes
>
>  include/phy.h | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/include/phy.h b/include/phy.h
> index 0543ec10c2..8f3e53db01 100644
> --- a/include/phy.h
> +++ b/include/phy.h
> @@ -50,6 +50,7 @@
>
>
>  typedef enum {
> +       PHY_INTERFACE_MODE_INTERNAL,

In Linux this is handled as a flag instead of a different mode. It
seems we should do it the same way.

>         PHY_INTERFACE_MODE_MII,
>         PHY_INTERFACE_MODE_GMII,
>         PHY_INTERFACE_MODE_SGMII,
> @@ -72,6 +73,7 @@ typedef enum {
>  } phy_interface_t;
>
>  static const char *phy_interface_strings[] = {
> +       [PHY_INTERFACE_MODE_INTERNAL]           = "internal",
>         [PHY_INTERFACE_MODE_MII]                = "mii",
>         [PHY_INTERFACE_MODE_GMII]               = "gmii",
>         [PHY_INTERFACE_MODE_SGMII]              = "sgmii",
> --
> 2.11.0
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 02/15] dma: add channels support
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 02/15] dma: add channels support Álvaro Fernández Rojas
@ 2018-03-07 21:27     ` Joe Hershberger
  2018-03-08 19:46       ` Álvaro Fernández Rojas
  2018-03-08 23:07     ` Grygorii Strashko
  2018-03-11 19:14     ` Daniel Schwierzeck
  2 siblings, 1 reply; 106+ messages in thread
From: Joe Hershberger @ 2018-03-07 21:27 UTC (permalink / raw)
  To: u-boot

On Mon, Mar 5, 2018 at 2:05 PM, Álvaro Fernández Rojas
<noltari@gmail.com> 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 <noltari@gmail.com>
> Reviewed-by: Simon Glass <sjg@chromium.org>
> ---
>  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, <www.ti.com>
> - *
> - * Author: Mugunthan V N <mugunthanvnm@ti.com>
> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
> + * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
>   *
>   * SPDX-License-Identifier:     GPL-2.0+
>   */
>
>  #include <common.h>
>  #include <dm.h>
> -#include <dm/uclass-internal.h>
> -#include <dm/device-internal.h>
> +#include <dm/read.h>
>  #include <dma-uclass.h>
> +#include <dt-structs.h>
>  #include <errno.h>
>
>  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, &dma->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,
> +                                        &args);
> +       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, &dev_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, &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);
> +       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, 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;

Isn't there a better error code you could return? Such as -ENOSYS like above?

> +
> +       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;

Same here.

> +
> +       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 3429f65ec4..b334adb68b 100644
> --- a/include/dma-uclass.h
> +++ b/include/dma-uclass.h
> @@ -13,6 +13,8 @@
>
>  #include <dma.h>
>
> +struct ofnode_phandle_args;
> +
>  /*
>   * struct dma_ops - Driver model DMA operations
>   *
> @@ -20,6 +22,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 ofnode_phandle_args *args);
> +       /**
> +        * request - Request a translated DMA.
> +        *
> +        * The DMA core calls this function as the second step in
> +        * implementing a client's dma_get_by_*() call, following a successful
> +        * xxx_xlate() call, or as the only step in implementing a client's
> +        * dma_request() call.
> +        *
> +        * @dma: The DMA struct to request; this has been filled in by
> +        *   a previoux xxx_xlate() function call, or by the caller of
> +        *   dma_request().
> +        * @return 0 if OK, or a negative error code.
> +        */
> +       int (*request)(struct dma *dma);
> +       /**
> +        * free - Free a previously requested dma.
> +        *
> +        * This is the implementation of the client dma_free() API.
> +        *
> +        * @dma: The DMA to free.
> +        * @return 0 if OK, or a negative error code.
> +        */
> +       int (*free)(struct dma *dma);
> +       /**
> +        * enable() - Enable a DMA Channel.
> +        *
> +        * @dma: The DMA Channel to manipulate.
> +        * @return zero on success, or -ve error code.
> +        */
> +       int (*enable)(struct dma *dma);
> +       /**
> +        * disable() - Disable a DMA Channel.
> +        *
> +        * @dma: The DMA Channel to manipulate.
> +        * @return zero on success, or -ve error code.
> +        */
> +       int (*disable)(struct dma *dma);
> +       /**
> +        * receive() - Receive a DMA transfer.
> +        *
> +        * @dma: The DMA Channel to manipulate.
> +        * @dst: The destination pointer.
> +        * @return zero on success, or -ve error code.
> +        */

I haven't seen any implementation of this. Will it return -EAGAIN in
the case where the packet isn't available?

> +       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);
> +#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, <www.ti.com>
> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
> + * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
>   *
>   * SPDX-License-Identifier:     GPL-2.0+
>   */
> @@ -8,6 +9,9 @@
>  #ifndef _DMA_H_
>  #define _DMA_H_
>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +
>  /*
>   * 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 provider. A provider will
> + * often implement multiple separate DMAs, since the hardware it manages
> + * often has this capability. dma_uclass.h describes the interface which
> + * DMA providers must implement.
> + *
> + * DMA consumers/clients are the HW modules driven by the DMA channels. This
> + * header file describes the API used by drivers for those HW modules.
> + */
> +
> +struct udevice;
> +
> +/**
> + * struct dma - A handle to (allowing control of) a single DMA.
> + *
> + * Clients provide storage for DMA handles. The content of the structure is
> + * managed solely by the DMA API and DMA drivers. A DMA struct is
> + * initialized by "get"ing the DMA struct. The DMA struct is passed to all
> + * other DMA APIs to identify which DMA channel to operate upon.
> + *
> + * @dev: The device which implements the DMA channel.
> + * @id: The DMA channel ID within the provider.
> + *
> + * Currently, the DMA API assumes that a single integer ID is enough to
> + * identify and configure any DMA channel for any DMA provider. If this
> + * assumption becomes invalid in the future, the struct could be expanded to
> + * either (a) add more fields to allow DMA providers to store additional
> + * information, or (b) replace the id field with an opaque pointer, which the
> + * provider would dynamically allocated during its .of_xlate op, and process
> + * during is .request op. This may require the addition of an extra op to clean
> + * up the allocation.
> + */
> +struct dma {
> +       struct udevice *dev;
> +       /*
> +        * Written by of_xlate. We assume a single id is enough for now. In the
> +        * future, we might add more fields here.
> +        */
> +       unsigned long id;
> +};
> +
> +# if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DMA)
> +struct phandle_1_arg;
> +int dma_get_by_index_platdata(struct udevice *dev, int index,
> +                             struct phandle_1_arg *cells, struct dma *dma);
> +
> +/**
> + * dma_get_by_index - Get/request a DMA by integer index.
> + *
> + * This looks up and requests a DMA. The index is relative to the client
> + * device; each device is assumed to have n DMAs associated with it somehow,
> + * and this function finds and requests one of them. The mapping of client
> + * device DMA indices to provider DMAs may be via device-tree properties,
> + * board-provided mapping tables, or some other mechanism.
> + *
> + * @dev:       The client device.
> + * @index:     The index of the DMA to request, within the client's list of
> + *             DMA channels.
> + * @dma:       A pointer to a DMA struct to initialize.
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_get_by_index(struct udevice *dev, int index, struct dma *dma);
> +
> +/**
> + * dma_get_by_name - Get/request a DMA by name.
> + *
> + * This looks up and requests a DMA. The name is relative to the client
> + * device; each device is assumed to have n DMAs associated with it somehow,
> + * and this function finds and requests one of them. The mapping of client
> + * device DMA names to provider DMAs may be via device-tree properties,
> + * board-provided mapping tables, or some other mechanism.
> + *
> + * @dev:       The client device.
> + * @name:      The name of the DMA to request, within the client's list of
> + *             DMA channels.
> + * @dma:       A pointer to a DMA struct to initialize.
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma);
> +# else
> +static inline int dma_get_by_index(struct udevice *dev, int index,
> +                                  struct dma *dma)
> +{
> +       return -ENOSYS;
> +}
> +
> +static inline int dma_get_by_name(struct udevice *dev, const char *name,
> +                          struct dma *dma)
> +{
> +       return -ENOSYS;
> +}
> +# endif
> +
> +/**
> + * dma_request - Request a DMA by provider-specific ID.
> + *
> + * This requests a DMA using a provider-specific ID. Generally, this function
> + * should not be used, since dma_get_by_index/name() provide an interface that
> + * better separates clients from intimate knowledge of DMA providers.
> + * However, this function may be useful in core SoC-specific code.
> + *
> + * @dev: The DMA provider device.
> + * @dma: A pointer to a DMA struct to initialize. The caller must
> + *      have already initialized any field in this struct which the
> + *      DMA provider uses to identify the DMA channel.
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_request(struct udevice *dev, struct dma *dma);
> +
> +/**
> + * dma_free - Free a previously requested DMA.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *      dma_request/get_by_*().
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_free(struct dma *dma);
> +
> +/**
> + * dma_enable() - Enable (turn on) a DMA channel.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *      dma_request/get_by_*().
> + * @return zero on success, or -ve error code.
> + */
> +int dma_enable(struct dma *dma);
> +
> +/**
> + * dma_disable() - Disable (turn off) a DMA channel.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *      dma_request/get_by_*().
> + * @return zero on success, or -ve error code.
> + */
> +int dma_disable(struct dma *dma);
> +
> +/**
> + * dma_receive() - Receive a DMA transfer.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *      dma_request/get_by_*().
> + * @dst: The destination pointer.
> + * @return zero on success, or -ve error code.
> + */
> +int dma_receive(struct dma *dma, void **dst);
> +
> +/**
> + * dma_send() - Send a DMA transfer.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *      dma_request/get_by_*().
> + * @src: The source pointer.
> + * @len: Length of the data to be sent (number of bytes).
> + * @return zero on success, or -ve error code.
> + */
> +int dma_send(struct dma *dma, void *src, size_t len);
> +#endif /* CONFIG_DMA_CHANNELS */
> +
>  /*
>   * dma_get_device - get a DMA device which supports transfer
>   * type of transfer_type
> --
> 2.11.0
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 08/15] net: add support for bcm6348-enet
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
@ 2018-03-07 21:46     ` Joe Hershberger
  2018-03-08 19:50       ` Álvaro Fernández Rojas
  0 siblings, 1 reply; 106+ messages in thread
From: Joe Hershberger @ 2018-03-07 21:46 UTC (permalink / raw)
  To: u-boot

On Mon, Mar 5, 2018 at 2:05 PM, Álvaro Fernández Rojas
<noltari@gmail.com> wrote:
> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
> ---
>  v5: Receive as much packets as possible from bcm6348-eth and cache them in
>  net_rx_packets. This is needed in order to fix flow control issues.
>  v4: Fix issues reported by Grygorii Strashko and other fixes:
>   - Copy received dma buffer to net_rx_packets in order to avoid possible
>   dma overwrites.
>   - Reset dma rx channel when sending a new packet to prevent flow control
>   issues.
>   - Fix packet casting on bcm6348_eth_recv/send.
>  v3: no changes
>  v2: select DMA_CHANNELS.
>
>  drivers/net/Kconfig            |  10 +
>  drivers/net/Makefile           |   1 +
>  drivers/net/bcm6348-eth.c      | 575 +++++++++++++++++++++++++++++++++++++++++
>  include/configs/bmips_common.h |   5 +-
>  4 files changed, 590 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/net/bcm6348-eth.c
>
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index de1947ccc1..e532332d78 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -71,6 +71,16 @@ config BCM_SF2_ETH_GMAC
>           by the BCM_SF2_ETH driver.
>           Say Y to any bcmcygnus based platforms.
>
> +config BCM6348_ETH
> +       bool "BCM6348 EMAC support"
> +       depends on DM_ETH && ARCH_BMIPS
> +       select DMA
> +       select DMA_CHANNELS
> +       select MII
> +       select PHYLIB
> +       help
> +         This driver supports the BCM6348 Ethernet MAC.
> +
>  config DWC_ETH_QOS
>         bool "Synopsys DWC Ethernet QOS device support"
>         depends on DM_ETH
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index ac5443c752..282adbc775 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -8,6 +8,7 @@
>  obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
>  obj-$(CONFIG_AG7XXX) += ag7xxx.o
>  obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
> +obj-$(CONFIG_BCM6348_ETH) += bcm6348-eth.o
>  obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
>  obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
>  obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
> diff --git a/drivers/net/bcm6348-eth.c b/drivers/net/bcm6348-eth.c
> new file mode 100644
> index 0000000000..43518f7b2d
> --- /dev/null
> +++ b/drivers/net/bcm6348-eth.c
> @@ -0,0 +1,575 @@
> +/*
> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
> + *
> + * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
> + *     Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <clk.h>
> +#include <dm.h>
> +#include <dma.h>
> +#include <miiphy.h>
> +#include <net.h>
> +#include <phy.h>
> +#include <reset.h>
> +#include <wait_bit.h>
> +#include <asm/io.h>
> +
> +#define ETH_RX_DESC                    PKTBUFSRX
> +#define ETH_MAX_MTU_SIZE               1518
> +#define ETH_TIMEOUT                    100
> +#define ETH_TX_WATERMARK               32
> +
> +/* ETH Receiver Configuration register */
> +#define ETH_RXCFG_REG                  0x00
> +#define ETH_RXCFG_ENFLOW_SHIFT         5
> +#define ETH_RXCFG_ENFLOW_MASK          (1 << ETH_RXCFG_ENFLOW_SHIFT)
> +
> +/* ETH Receive Maximum Length register */
> +#define ETH_RXMAXLEN_REG               0x04
> +#define ETH_RXMAXLEN_SHIFT             0
> +#define ETH_RXMAXLEN_MASK              (0x7ff << ETH_RXMAXLEN_SHIFT)
> +
> +/* ETH Transmit Maximum Length register */
> +#define ETH_TXMAXLEN_REG               0x08
> +#define ETH_TXMAXLEN_SHIFT             0
> +#define ETH_TXMAXLEN_MASK              (0x7ff << ETH_TXMAXLEN_SHIFT)
> +
> +/* MII Status/Control register */
> +#define MII_SC_REG                     0x10
> +#define MII_SC_MDCFREQDIV_SHIFT                0
> +#define MII_SC_MDCFREQDIV_MASK         (0x7f << MII_SC_MDCFREQDIV_SHIFT)
> +#define MII_SC_PREAMBLE_EN_SHIFT       7
> +#define MII_SC_PREAMBLE_EN_MASK                (1 << MII_SC_PREAMBLE_EN_SHIFT)
> +
> +/* MII Data register */
> +#define MII_DAT_REG                    0x14
> +#define MII_DAT_DATA_SHIFT             0
> +#define MII_DAT_DATA_MASK              (0xffff << MII_DAT_DATA_SHIFT)
> +#define MII_DAT_TA_SHIFT               16
> +#define MII_DAT_TA_MASK                        (0x3 << MII_DAT_TA_SHIFT)
> +#define MII_DAT_REG_SHIFT              18
> +#define MII_DAT_REG_MASK               (0x1f << MII_DAT_REG_SHIFT)
> +#define MII_DAT_PHY_SHIFT              23
> +#define MII_DAT_PHY_MASK               (0x1f << MII_DAT_PHY_SHIFT)
> +#define MII_DAT_OP_SHIFT               28
> +#define MII_DAT_OP_WRITE               (0x5 << MII_DAT_OP_SHIFT)
> +#define MII_DAT_OP_READ                        (0x6 << MII_DAT_OP_SHIFT)
> +
> +/* ETH Interrupts Mask register */
> +#define ETH_IRMASK_REG                 0x18
> +
> +/* ETH Interrupts register */
> +#define ETH_IR_REG                     0x1c
> +#define ETH_IR_MII_SHIFT               0
> +#define ETH_IR_MII_MASK                        (1 << ETH_IR_MII_SHIFT)
> +
> +/* ETH Control register */
> +#define ETH_CTL_REG                    0x2c
> +#define ETH_CTL_ENABLE_SHIFT           0
> +#define ETH_CTL_ENABLE_MASK            (1 << ETH_CTL_ENABLE_SHIFT)
> +#define ETH_CTL_DISABLE_SHIFT          1
> +#define ETH_CTL_DISABLE_MASK           (1 << ETH_CTL_DISABLE_SHIFT)
> +#define ETH_CTL_RESET_SHIFT            2
> +#define ETH_CTL_RESET_MASK             (1 << ETH_CTL_RESET_SHIFT)
> +#define ETH_CTL_EPHY_SHIFT             3
> +#define ETH_CTL_EPHY_MASK              (1 << ETH_CTL_EPHY_SHIFT)
> +
> +/* ETH Transmit Control register */
> +#define ETH_TXCTL_REG                  0x30
> +#define ETH_TXCTL_FD_SHIFT             0
> +#define ETH_TXCTL_FD_MASK              (1 << ETH_TXCTL_FD_SHIFT)
> +
> +/* ETH Transmit Watermask register */
> +#define ETH_TXWMARK_REG                        0x34
> +#define ETH_TXWMARK_WM_SHIFT           0
> +#define ETH_TXWMARK_WM_MASK            (0x3f << ETH_TXWMARK_WM_SHIFT)
> +
> +/* MIB Control register */
> +#define MIB_CTL_REG                    0x38
> +#define MIB_CTL_RDCLEAR_SHIFT          0
> +#define MIB_CTL_RDCLEAR_MASK           (1 << MIB_CTL_RDCLEAR_SHIFT)
> +
> +/* ETH Perfect Match registers */
> +#define ETH_PM_CNT                     4
> +#define ETH_PML_REG(x)                 (0x58 + (x) * 0x8)
> +#define ETH_PMH_REG(x)                 (0x5c + (x) * 0x8)
> +#define ETH_PMH_VALID_SHIFT            16
> +#define ETH_PMH_VALID_MASK             (1 << ETH_PMH_VALID_SHIFT)
> +
> +/* MIB Counters registers */
> +#define MIB_REG_CNT                    55
> +#define MIB_REG(x)                     (0x200 + (x) * 4)
> +
> +/* ETH data */
> +struct bcm6348_eth_priv {
> +       void __iomem *base;
> +       /* RX */
> +       uint8_t rx_desc;
> +       uint8_t rx_pend;
> +       int rx_ret[ETH_RX_DESC];
> +       /* DMA */
> +       struct dma rx_dma;
> +       struct dma tx_dma;
> +       /* PHY */
> +       int phy_id;
> +       struct phy_device *phy_dev;
> +};
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +static void bcm6348_eth_mac_disable(struct bcm6348_eth_priv *priv)
> +{
> +       /* disable emac */
> +       clrsetbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK,
> +                       ETH_CTL_DISABLE_MASK);
> +
> +       /* wait until emac is disabled */
> +       if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
> +                             ETH_CTL_DISABLE_MASK, false,
> +                             ETH_TIMEOUT, false))
> +               pr_err("error disabling emac\n");
> +}
> +
> +static void bcm6348_eth_mac_enable(struct bcm6348_eth_priv *priv)
> +{
> +       setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK);
> +}
> +
> +static void bcm6348_eth_mac_reset(struct bcm6348_eth_priv *priv)
> +{
> +       /* reset emac */
> +       writel_be(ETH_CTL_RESET_MASK, priv->base + ETH_CTL_REG);
> +       wmb();
> +
> +       /* wait until emac is reset */
> +       if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
> +                             ETH_CTL_RESET_MASK, false,
> +                             ETH_TIMEOUT, false))
> +               pr_err("error resetting emac\n");
> +}
> +
> +static int bcm6348_eth_free_pkt(struct udevice *dev, uchar *packet, int len)
> +{
> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
> +
> +       /* sanity check */
> +       if (packet != net_rx_packets[priv->rx_pend]) {
> +               pr_err("rx_pend %d: packet is not matched,\n", priv->rx_pend);
> +               return -EAGAIN;
> +       }
> +
> +       /* free pending packet */
> +       priv->rx_ret[priv->rx_pend] = 0;
> +       priv->rx_pend = (priv->rx_pend + 1) % ETH_RX_DESC;
> +
> +       return 0;
> +}
> +
> +static int _bcm6348_eth_recv(struct bcm6348_eth_priv *priv)
> +{
> +       uint8_t pkt = priv->rx_desc;
> +
> +       /* check if packet is free */
> +       if (priv->rx_ret[pkt] > 0)
> +               return -EAGAIN;
> +
> +       /* try to receive a new packet */
> +       priv->rx_ret[pkt] = dma_receive(&priv->rx_dma,
> +                                       (void **)&net_rx_packets[pkt]);
> +       if (priv->rx_ret[pkt] > 0)
> +               priv->rx_desc = (priv->rx_desc + 1) % ETH_RX_DESC;
> +
> +       return priv->rx_ret[pkt];
> +}
> +
> +static int bcm6348_eth_recv(struct udevice *dev, int flags, uchar **packetp)
> +{
> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
> +       uint8_t pkt_cnt = 0;
> +       int ret;
> +
> +       /* try to receive packets */
> +       while (_bcm6348_eth_recv(priv) > 0)
> +               pkt_cnt++;
> +
> +       if (pkt_cnt)
> +               debug("%s: received %u packet(s)\n", __func__, pkt_cnt);
> +
> +       /* return current packet */
> +       ret = priv->rx_ret[priv->rx_pend];
> +       if (ret > 0)
> +               *packetp = net_rx_packets[priv->rx_pend];
> +
> +       return ret;
> +}
> +
> +static int bcm6348_eth_send(struct udevice *dev, void *packet, int length)
> +{
> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
> +
> +       /* reset dma rx channel */
> +       dma_disable(&priv->rx_dma);
> +       dma_enable(&priv->rx_dma);

Why. Please include reasoning in the comment.

> +
> +       return dma_send(&priv->tx_dma, (void *)packet, length);
> +}
> +
> +static int bcm6348_eth_adjust_link(struct udevice *dev,
> +                                  struct phy_device *phydev)
> +{
> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
> +
> +       /* mac duplex parameters */
> +       if (phydev->duplex)
> +               setbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
> +       else
> +               clrbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
> +
> +       /* rx flow control (pause frame handling) */
> +       if (phydev->pause)
> +               setbits_be32(priv->base + ETH_RXCFG_REG,
> +                            ETH_RXCFG_ENFLOW_MASK);
> +       else
> +               clrbits_be32(priv->base + ETH_RXCFG_REG,
> +                            ETH_RXCFG_ENFLOW_MASK);
> +
> +       return 0;
> +}
> +
> +static int bcm6348_eth_start(struct udevice *dev)
> +{
> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
> +       int ret, i;
> +
> +       priv->rx_desc = 0;
> +       priv->rx_pend = 0;
> +       for (i = 0; i < ETH_RX_DESC; i++)
> +               priv->rx_ret[i] = 0;
> +
> +       /* enable dma rx channel */
> +       dma_enable(&priv->rx_dma);
> +
> +       /* enable dma tx channel */
> +       dma_enable(&priv->tx_dma);
> +
> +       ret = phy_startup(priv->phy_dev);
> +       if (ret) {
> +               pr_err("could not initialize phy\n");
> +               return ret;
> +       }
> +
> +       if (!priv->phy_dev->link) {
> +               pr_err("no phy link\n");
> +               return -EIO;
> +       }
> +
> +       bcm6348_eth_adjust_link(dev, priv->phy_dev);
> +
> +       /* zero mib counters */
> +       for (i = 0; i < MIB_REG_CNT; i++)
> +               writel_be(0, MIB_REG(i));
> +
> +       /* enable rx flow control */
> +       setbits_be32(priv->base + ETH_RXCFG_REG, ETH_RXCFG_ENFLOW_MASK);
> +
> +       /* set max rx/tx length */
> +       writel_be((ETH_MAX_MTU_SIZE << ETH_RXMAXLEN_SHIFT) &
> +                 ETH_RXMAXLEN_MASK, priv->base + ETH_RXMAXLEN_REG);
> +       writel_be((ETH_MAX_MTU_SIZE << ETH_TXMAXLEN_SHIFT) &
> +                  ETH_TXMAXLEN_MASK, priv->base + ETH_TXMAXLEN_REG);
> +
> +       /* set correct transmit fifo watermark */
> +       writel_be((ETH_TX_WATERMARK << ETH_TXWMARK_WM_SHIFT) &
> +                 ETH_TXWMARK_WM_MASK, priv->base + ETH_TXWMARK_REG);
> +
> +       /* enable emac */
> +       bcm6348_eth_mac_enable(priv);
> +
> +       /* clear interrupts */
> +       writel_be(0, priv->base + ETH_IRMASK_REG);
> +
> +       return 0;
> +}
> +
> +static void bcm6348_eth_stop(struct udevice *dev)
> +{
> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
> +
> +       /* disable dma rx channel */
> +       dma_disable(&priv->rx_dma);
> +
> +       /* disable dma tx channel */
> +       dma_disable(&priv->tx_dma);
> +
> +       /* disable emac */
> +       bcm6348_eth_mac_disable(priv);
> +}
> +
> +static int bcm6348_eth_write_hwaddr(struct udevice *dev)
> +{
> +       struct eth_pdata *pdata = dev_get_platdata(dev);
> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
> +       bool running = false;
> +
> +       /* check if emac is running */
> +       if (readl_be(priv->base + ETH_CTL_REG) & ETH_CTL_ENABLE_MASK)
> +               running = true;
> +
> +       /* disable emac */
> +       if (running)
> +               bcm6348_eth_mac_disable(priv);
> +
> +       /* set mac address */
> +       writel_be((pdata->enetaddr[2] << 24) | (pdata->enetaddr[3]) << 16 |
> +                 (pdata->enetaddr[4]) << 8 | (pdata->enetaddr[5]),
> +                 priv->base + ETH_PML_REG(0));
> +       writel_be((pdata->enetaddr[1]) | (pdata->enetaddr[0] << 8) |
> +                 ETH_PMH_VALID_MASK, priv->base + ETH_PMH_REG(0));
> +
> +       /* enable emac */
> +       if (running)
> +               bcm6348_eth_mac_enable(priv);
> +
> +       return 0;
> +}
> +
> +static const struct eth_ops bcm6348_eth_ops = {
> +       .free_pkt = bcm6348_eth_free_pkt,
> +       .recv = bcm6348_eth_recv,
> +       .send = bcm6348_eth_send,
> +       .start = bcm6348_eth_start,
> +       .stop = bcm6348_eth_stop,
> +       .write_hwaddr = bcm6348_eth_write_hwaddr,
> +};
> +
> +static const struct udevice_id bcm6348_eth_ids[] = {
> +       { .compatible = "brcm,bcm6348-enet", },
> +       { /* sentinel */ }
> +};
> +
> +static int bcm6348_mdio_op(void __iomem *base, uint32_t data)
> +{
> +       /* make sure mii interrupt status is cleared */
> +       writel_be(ETH_IR_MII_MASK, base + ETH_IR_REG);
> +
> +       /* issue mii op */
> +       writel_be(data, base + MII_DAT_REG);
> +
> +       /* wait until emac is disabled */
> +       return wait_for_bit_be32(base + ETH_IR_REG,
> +                                ETH_IR_MII_MASK, true,
> +                                ETH_TIMEOUT, false);
> +}
> +
> +static int bcm6348_mdio_read(struct mii_dev *bus, int addr, int devaddr,
> +                            int reg)
> +{
> +       void __iomem *base = bus->priv;
> +       uint32_t val;
> +
> +       val = MII_DAT_OP_READ;
> +       val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
> +       val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
> +       val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
> +
> +       if (bcm6348_mdio_op(base, val)) {
> +               pr_err("%s: timeout\n", __func__);
> +               return -EINVAL;
> +       }
> +
> +       val = readl_be(base + MII_DAT_REG) & MII_DAT_DATA_MASK;
> +       val >>= MII_DAT_DATA_SHIFT;
> +
> +       return val;
> +}
> +
> +static int bcm6348_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
> +                             int reg, u16 value)
> +{
> +       void __iomem *base = bus->priv;
> +       uint32_t val;
> +
> +       val = MII_DAT_OP_WRITE;
> +       val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
> +       val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
> +       val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
> +       val |= (value << MII_DAT_DATA_SHIFT) & MII_DAT_DATA_MASK;
> +
> +       if (bcm6348_mdio_op(base, val)) {
> +               pr_err("%s: timeout\n", __func__);
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static int bcm6348_mdio_init(const char *name, void __iomem *base)
> +{
> +       struct mii_dev *bus;
> +
> +       bus = mdio_alloc();
> +       if (!bus) {
> +               pr_err("%s: failed to allocate MDIO bus\n", __func__);
> +               return -ENOMEM;
> +       }
> +
> +       bus->read = bcm6348_mdio_read;
> +       bus->write = bcm6348_mdio_write;
> +       bus->priv = base;
> +       snprintf(bus->name, sizeof(bus->name), "%s", name);
> +
> +       return mdio_register(bus);
> +}
> +
> +static int bcm6348_phy_init(struct udevice *dev)
> +{
> +       struct eth_pdata *pdata = dev_get_platdata(dev);
> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
> +       struct mii_dev *bus;
> +
> +       /* get mii bus */
> +       bus = miiphy_get_dev_by_name(dev->name);
> +
> +       /* phy connect */
> +       priv->phy_dev = phy_connect(bus, priv->phy_id, dev,
> +                                   pdata->phy_interface);
> +       if (!priv->phy_dev) {
> +               pr_err("%s: no phy device\n", __func__);
> +               return -ENODEV;
> +       }
> +
> +       priv->phy_dev->supported = (SUPPORTED_10baseT_Half |
> +                                   SUPPORTED_10baseT_Full |
> +                                   SUPPORTED_100baseT_Half |
> +                                   SUPPORTED_100baseT_Full |
> +                                   SUPPORTED_Autoneg |
> +                                   SUPPORTED_Pause |
> +                                   SUPPORTED_MII);
> +       priv->phy_dev->advertising = priv->phy_dev->supported;
> +
> +       /* phy config */
> +       phy_config(priv->phy_dev);
> +
> +       return 0;
> +}
> +
> +static int bcm6348_eth_probe(struct udevice *dev)
> +{
> +       struct eth_pdata *pdata = dev_get_platdata(dev);
> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
> +       void *blob = (void *)gd->fdt_blob;
> +       int node = dev_of_offset(dev);
> +       const char *phy_mode;
> +       fdt_addr_t addr;
> +       int phy_node, ret, i;
> +
> +       /* get base address */
> +       addr = devfdt_get_addr(dev);
> +       if (addr == FDT_ADDR_T_NONE)
> +               return -EINVAL;
> +
> +       /* get phy mode */
> +       pdata->phy_interface = PHY_INTERFACE_MODE_NONE;
> +       phy_mode = fdt_getprop(blob, node, "phy-mode", NULL);
> +       if (phy_mode)
> +               pdata->phy_interface = phy_get_interface_by_name(phy_mode);
> +       if (pdata->phy_interface == PHY_INTERFACE_MODE_NONE)
> +               return -ENODEV;
> +
> +       /* get phy */
> +       phy_node = fdtdec_lookup_phandle(blob, node, "phy");
> +       if (phy_node >= 0)
> +               priv->phy_id = fdtdec_get_int(blob, phy_node, "reg", -1);
> +       else
> +               return -EINVAL;
> +
> +       /* get dma channels */
> +       ret = dma_get_by_name(dev, "tx", &priv->tx_dma);
> +       if (ret)
> +               return -EINVAL;
> +
> +       ret = dma_get_by_name(dev, "rx", &priv->rx_dma);
> +       if (ret)
> +               return -EINVAL;
> +
> +       /* try to enable clocks */
> +       for (i = 0; ; i++) {
> +               struct clk clk;
> +               int ret;
> +
> +               ret = clk_get_by_index(dev, i, &clk);
> +               if (ret < 0)
> +                       break;
> +               if (clk_enable(&clk))
> +                       pr_err("failed to enable clock %d\n", i);
> +               clk_free(&clk);
> +       }
> +
> +       /* try to perform resets */
> +       for (i = 0; ; i++) {
> +               struct reset_ctl reset;
> +               int ret;
> +
> +               ret = reset_get_by_index(dev, i, &reset);
> +               if (ret < 0)
> +                       break;
> +               if (reset_deassert(&reset))
> +                       pr_err("failed to deassert reset %d\n", i);
> +               reset_free(&reset);
> +       }
> +
> +       /* get base addr */
> +       priv->base = ioremap(addr, 0);
> +       pdata->iobase = (phys_addr_t) priv->base;
> +
> +       /* disable emac */
> +       bcm6348_eth_mac_disable(priv);
> +
> +       /* reset emac */
> +       bcm6348_eth_mac_reset(priv);
> +
> +       /* select correct mii interface */
> +       if (pdata->phy_interface == PHY_INTERFACE_MODE_INTERNAL)
> +               clrbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
> +       else
> +               setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
> +
> +       /* turn on mdc clock */
> +       writel_be((0x1f << MII_SC_MDCFREQDIV_SHIFT) |
> +                 MII_SC_PREAMBLE_EN_MASK, priv->base + MII_SC_REG);
> +
> +       /* set mib counters to not clear when read */
> +       clrbits_be32(priv->base + MIB_CTL_REG, MIB_CTL_RDCLEAR_MASK);
> +
> +       /* initialize perfect match registers */
> +       for (i = 0; i < ETH_PM_CNT; i++) {
> +               writel_be(0, priv->base + ETH_PML_REG(i));
> +               writel_be(0, priv->base + ETH_PMH_REG(i));
> +       }
> +
> +       /* init mii bus */
> +       ret = bcm6348_mdio_init(dev->name, priv->base);
> +       if (ret)
> +               return ret;
> +
> +       /* init phy */
> +       ret = bcm6348_phy_init(dev);
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +U_BOOT_DRIVER(bcm6348_eth) = {
> +       .name = "bcm6348_eth",
> +       .id = UCLASS_ETH,
> +       .of_match = bcm6348_eth_ids,
> +       .ops = &bcm6348_eth_ops,
> +       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
> +       .priv_auto_alloc_size = sizeof(struct bcm6348_eth_priv),
> +       .probe = bcm6348_eth_probe,
> +};
> diff --git a/include/configs/bmips_common.h b/include/configs/bmips_common.h
> index 38bf7a272b..eb66512f67 100644
> --- a/include/configs/bmips_common.h
> +++ b/include/configs/bmips_common.h
> @@ -7,6 +7,9 @@
>  #ifndef __CONFIG_BMIPS_COMMON_H
>  #define __CONFIG_BMIPS_COMMON_H
>
> +/* ETH */
> +#define CONFIG_PHY_RESET_DELAY         20
> +
>  /* UART */
>  #define CONFIG_SYS_BAUDRATE_TABLE      { 9600, 19200, 38400, 57600, 115200, \
>                                           230400, 500000, 1500000 }
> @@ -17,7 +20,7 @@
>
>  /* Memory usage */
>  #define CONFIG_SYS_MAXARGS             24
> -#define CONFIG_SYS_MALLOC_LEN          (1024 * 1024)
> +#define CONFIG_SYS_MALLOC_LEN          (2 * 1024 * 1024)
>  #define CONFIG_SYS_BOOTPARAMS_LEN      (128 * 1024)
>  #define CONFIG_SYS_CBSIZE              512
>
> --
> 2.11.0
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 07/15] phy: add support for internal phys
  2018-03-07 20:28     ` Joe Hershberger
@ 2018-03-08 19:38       ` Álvaro Fernández Rojas
  2018-03-08 20:11         ` Joe Hershberger
  0 siblings, 1 reply; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-08 19:38 UTC (permalink / raw)
  To: u-boot

Hi Joe,

El 07/03/2018 a las 21:28, Joe Hershberger escribió:
> On Mon, Mar 5, 2018 at 2:05 PM, Álvaro Fernández Rojas
> <noltari@gmail.com> wrote:
>> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
>> ---
>>   v5: no changes
>>   v4: no changes
>>   v3: no changes
>>   v2: no changes
>>
>>   include/phy.h | 2 ++
>>   1 file changed, 2 insertions(+)
>>
>> diff --git a/include/phy.h b/include/phy.h
>> index 0543ec10c2..8f3e53db01 100644
>> --- a/include/phy.h
>> +++ b/include/phy.h
>> @@ -50,6 +50,7 @@
>>
>>
>>   typedef enum {
>> +       PHY_INTERFACE_MODE_INTERNAL,
> In Linux this is handled as a flag instead of a different mode. It
> seems we should do it the same way.
Not really, in Linux this is handled as both:
- As a flag (https://elixir.bootlin.com/linux/latest/ident/PHY_IS_INTERNAL):
https://github.com/torvalds/linux/blob/master/include/linux/phy.h#L61
https://github.com/torvalds/linux/blob/master/drivers/net/phy/phy_device.c#L1792
https://github.com/torvalds/linux/blob/master/include/linux/phy.h#L832
- As a mode 
(https://elixir.bootlin.com/linux/latest/ident/PHY_INTERFACE_MODE_INTERNAL):
https://github.com/torvalds/linux/blob/master/include/linux/phy.h#L68
https://github.com/torvalds/linux/blob/master/include/linux/phy.h#L119

>
>>          PHY_INTERFACE_MODE_MII,
>>          PHY_INTERFACE_MODE_GMII,
>>          PHY_INTERFACE_MODE_SGMII,
>> @@ -72,6 +73,7 @@ typedef enum {
>>   } phy_interface_t;
>>
>>   static const char *phy_interface_strings[] = {
>> +       [PHY_INTERFACE_MODE_INTERNAL]           = "internal",
>>          [PHY_INTERFACE_MODE_MII]                = "mii",
>>          [PHY_INTERFACE_MODE_GMII]               = "gmii",
>>          [PHY_INTERFACE_MODE_SGMII]              = "sgmii",
>> --
>> 2.11.0
>>
>> _______________________________________________
>> U-Boot mailing list
>> U-Boot at lists.denx.de
>> https://lists.denx.de/listinfo/u-boot
~Álvaro.

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 02/15] dma: add channels support
  2018-03-07 21:27     ` Joe Hershberger
@ 2018-03-08 19:46       ` Álvaro Fernández Rojas
  0 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-08 19:46 UTC (permalink / raw)
  To: u-boot

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
> <noltari@gmail.com> 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 <noltari@gmail.com>
>> Reviewed-by: Simon Glass <sjg@chromium.org>
>> ---
>>   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, <www.ti.com>
>> - *
>> - * Author: Mugunthan V N <mugunthanvnm@ti.com>
>> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
>> + * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
>> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
>>    *
>>    * SPDX-License-Identifier:     GPL-2.0+
>>    */
>>
>>   #include <common.h>
>>   #include <dm.h>
>> -#include <dm/uclass-internal.h>
>> -#include <dm/device-internal.h>
>> +#include <dm/read.h>
>>   #include <dma-uclass.h>
>> +#include <dt-structs.h>
>>   #include <errno.h>
>>
>>   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, &dma->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,
>> +                                        &args);
>> +       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, &dev_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, &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);
>> +       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, 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;
> Isn't there a better error code you could return? Such as -ENOSYS like above?
Ok, I will fix that in the next version.
>
>> +
>> +       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;
> Same here.
Ok, I will fix that in the next version.
>
>> +
>> +       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 3429f65ec4..b334adb68b 100644
>> --- a/include/dma-uclass.h
>> +++ b/include/dma-uclass.h
>> @@ -13,6 +13,8 @@
>>
>>   #include <dma.h>
>>
>> +struct ofnode_phandle_args;
>> +
>>   /*
>>    * struct dma_ops - Driver model DMA operations
>>    *
>> @@ -20,6 +22,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 ofnode_phandle_args *args);
>> +       /**
>> +        * request - Request a translated DMA.
>> +        *
>> +        * The DMA core calls this function as the second step in
>> +        * implementing a client's dma_get_by_*() call, following a successful
>> +        * xxx_xlate() call, or as the only step in implementing a client's
>> +        * dma_request() call.
>> +        *
>> +        * @dma: The DMA struct to request; this has been filled in by
>> +        *   a previoux xxx_xlate() function call, or by the caller of
>> +        *   dma_request().
>> +        * @return 0 if OK, or a negative error code.
>> +        */
>> +       int (*request)(struct dma *dma);
>> +       /**
>> +        * free - Free a previously requested dma.
>> +        *
>> +        * This is the implementation of the client dma_free() API.
>> +        *
>> +        * @dma: The DMA to free.
>> +        * @return 0 if OK, or a negative error code.
>> +        */
>> +       int (*free)(struct dma *dma);
>> +       /**
>> +        * enable() - Enable a DMA Channel.
>> +        *
>> +        * @dma: The DMA Channel to manipulate.
>> +        * @return zero on success, or -ve error code.
>> +        */
>> +       int (*enable)(struct dma *dma);
>> +       /**
>> +        * disable() - Disable a DMA Channel.
>> +        *
>> +        * @dma: The DMA Channel to manipulate.
>> +        * @return zero on success, or -ve error code.
>> +        */
>> +       int (*disable)(struct dma *dma);
>> +       /**
>> +        * receive() - Receive a DMA transfer.
>> +        *
>> +        * @dma: The DMA Channel to manipulate.
>> +        * @dst: The destination pointer.
>> +        * @return zero on success, or -ve error code.
>> +        */
> I haven't seen any implementation of this. Will it return -EAGAIN in
> the case where the packet isn't available?
First of all, this documentation is wrong, because it doesn't return 
zero on success, but the received packet length, and it returns -EAGAIN 
when packet is not available in order to facilitate enet 
implementations, but it can return something different and handle it 
from enet drivers.
I will fix that in the next version.
>
>> +       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);
>> +#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, <www.ti.com>
>> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
>> + * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
>> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
>>    *
>>    * SPDX-License-Identifier:     GPL-2.0+
>>    */
>> @@ -8,6 +9,9 @@
>>   #ifndef _DMA_H_
>>   #define _DMA_H_
>>
>> +#include <linux/errno.h>
>> +#include <linux/types.h>
>> +
>>   /*
>>    * 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 provider. A provider will
>> + * often implement multiple separate DMAs, since the hardware it manages
>> + * often has this capability. dma_uclass.h describes the interface which
>> + * DMA providers must implement.
>> + *
>> + * DMA consumers/clients are the HW modules driven by the DMA channels. This
>> + * header file describes the API used by drivers for those HW modules.
>> + */
>> +
>> +struct udevice;
>> +
>> +/**
>> + * struct dma - A handle to (allowing control of) a single DMA.
>> + *
>> + * Clients provide storage for DMA handles. The content of the structure is
>> + * managed solely by the DMA API and DMA drivers. A DMA struct is
>> + * initialized by "get"ing the DMA struct. The DMA struct is passed to all
>> + * other DMA APIs to identify which DMA channel to operate upon.
>> + *
>> + * @dev: The device which implements the DMA channel.
>> + * @id: The DMA channel ID within the provider.
>> + *
>> + * Currently, the DMA API assumes that a single integer ID is enough to
>> + * identify and configure any DMA channel for any DMA provider. If this
>> + * assumption becomes invalid in the future, the struct could be expanded to
>> + * either (a) add more fields to allow DMA providers to store additional
>> + * information, or (b) replace the id field with an opaque pointer, which the
>> + * provider would dynamically allocated during its .of_xlate op, and process
>> + * during is .request op. This may require the addition of an extra op to clean
>> + * up the allocation.
>> + */
>> +struct dma {
>> +       struct udevice *dev;
>> +       /*
>> +        * Written by of_xlate. We assume a single id is enough for now. In the
>> +        * future, we might add more fields here.
>> +        */
>> +       unsigned long id;
>> +};
>> +
>> +# if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DMA)
>> +struct phandle_1_arg;
>> +int dma_get_by_index_platdata(struct udevice *dev, int index,
>> +                             struct phandle_1_arg *cells, struct dma *dma);
>> +
>> +/**
>> + * dma_get_by_index - Get/request a DMA by integer index.
>> + *
>> + * This looks up and requests a DMA. The index is relative to the client
>> + * device; each device is assumed to have n DMAs associated with it somehow,
>> + * and this function finds and requests one of them. The mapping of client
>> + * device DMA indices to provider DMAs may be via device-tree properties,
>> + * board-provided mapping tables, or some other mechanism.
>> + *
>> + * @dev:       The client device.
>> + * @index:     The index of the DMA to request, within the client's list of
>> + *             DMA channels.
>> + * @dma:       A pointer to a DMA struct to initialize.
>> + * @return 0 if OK, or a negative error code.
>> + */
>> +int dma_get_by_index(struct udevice *dev, int index, struct dma *dma);
>> +
>> +/**
>> + * dma_get_by_name - Get/request a DMA by name.
>> + *
>> + * This looks up and requests a DMA. The name is relative to the client
>> + * device; each device is assumed to have n DMAs associated with it somehow,
>> + * and this function finds and requests one of them. The mapping of client
>> + * device DMA names to provider DMAs may be via device-tree properties,
>> + * board-provided mapping tables, or some other mechanism.
>> + *
>> + * @dev:       The client device.
>> + * @name:      The name of the DMA to request, within the client's list of
>> + *             DMA channels.
>> + * @dma:       A pointer to a DMA struct to initialize.
>> + * @return 0 if OK, or a negative error code.
>> + */
>> +int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma);
>> +# else
>> +static inline int dma_get_by_index(struct udevice *dev, int index,
>> +                                  struct dma *dma)
>> +{
>> +       return -ENOSYS;
>> +}
>> +
>> +static inline int dma_get_by_name(struct udevice *dev, const char *name,
>> +                          struct dma *dma)
>> +{
>> +       return -ENOSYS;
>> +}
>> +# endif
>> +
>> +/**
>> + * dma_request - Request a DMA by provider-specific ID.
>> + *
>> + * This requests a DMA using a provider-specific ID. Generally, this function
>> + * should not be used, since dma_get_by_index/name() provide an interface that
>> + * better separates clients from intimate knowledge of DMA providers.
>> + * However, this function may be useful in core SoC-specific code.
>> + *
>> + * @dev: The DMA provider device.
>> + * @dma: A pointer to a DMA struct to initialize. The caller must
>> + *      have already initialized any field in this struct which the
>> + *      DMA provider uses to identify the DMA channel.
>> + * @return 0 if OK, or a negative error code.
>> + */
>> +int dma_request(struct udevice *dev, struct dma *dma);
>> +
>> +/**
>> + * dma_free - Free a previously requested DMA.
>> + *
>> + * @dma: A DMA struct that was previously successfully requested by
>> + *      dma_request/get_by_*().
>> + * @return 0 if OK, or a negative error code.
>> + */
>> +int dma_free(struct dma *dma);
>> +
>> +/**
>> + * dma_enable() - Enable (turn on) a DMA channel.
>> + *
>> + * @dma: A DMA struct that was previously successfully requested by
>> + *      dma_request/get_by_*().
>> + * @return zero on success, or -ve error code.
>> + */
>> +int dma_enable(struct dma *dma);
>> +
>> +/**
>> + * dma_disable() - Disable (turn off) a DMA channel.
>> + *
>> + * @dma: A DMA struct that was previously successfully requested by
>> + *      dma_request/get_by_*().
>> + * @return zero on success, or -ve error code.
>> + */
>> +int dma_disable(struct dma *dma);
>> +
>> +/**
>> + * dma_receive() - Receive a DMA transfer.
>> + *
>> + * @dma: A DMA struct that was previously successfully requested by
>> + *      dma_request/get_by_*().
>> + * @dst: The destination pointer.
>> + * @return zero on success, or -ve error code.
>> + */
>> +int dma_receive(struct dma *dma, void **dst);
>> +
>> +/**
>> + * dma_send() - Send a DMA transfer.
>> + *
>> + * @dma: A DMA struct that was previously successfully requested by
>> + *      dma_request/get_by_*().
>> + * @src: The source pointer.
>> + * @len: Length of the data to be sent (number of bytes).
>> + * @return zero on success, or -ve error code.
>> + */
>> +int dma_send(struct dma *dma, void *src, size_t len);
>> +#endif /* CONFIG_DMA_CHANNELS */
>> +
>>   /*
>>    * dma_get_device - get a DMA device which supports transfer
>>    * type of transfer_type
>> --
>> 2.11.0
>>
>> _______________________________________________
>> U-Boot mailing list
>> U-Boot at lists.denx.de
>> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 08/15] net: add support for bcm6348-enet
  2018-03-07 21:46     ` Joe Hershberger
@ 2018-03-08 19:50       ` Álvaro Fernández Rojas
  0 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-08 19:50 UTC (permalink / raw)
  To: u-boot

Hi Joe,

El 07/03/2018 a las 22:46, Joe Hershberger escribió:
> On Mon, Mar 5, 2018 at 2:05 PM, Álvaro Fernández Rojas
> <noltari@gmail.com> wrote:
>> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
>> ---
>>   v5: Receive as much packets as possible from bcm6348-eth and cache them in
>>   net_rx_packets. This is needed in order to fix flow control issues.
>>   v4: Fix issues reported by Grygorii Strashko and other fixes:
>>    - Copy received dma buffer to net_rx_packets in order to avoid possible
>>    dma overwrites.
>>    - Reset dma rx channel when sending a new packet to prevent flow control
>>    issues.
>>    - Fix packet casting on bcm6348_eth_recv/send.
>>   v3: no changes
>>   v2: select DMA_CHANNELS.
>>
>>   drivers/net/Kconfig            |  10 +
>>   drivers/net/Makefile           |   1 +
>>   drivers/net/bcm6348-eth.c      | 575 +++++++++++++++++++++++++++++++++++++++++
>>   include/configs/bmips_common.h |   5 +-
>>   4 files changed, 590 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/net/bcm6348-eth.c
>>
>> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
>> index de1947ccc1..e532332d78 100644
>> --- a/drivers/net/Kconfig
>> +++ b/drivers/net/Kconfig
>> @@ -71,6 +71,16 @@ config BCM_SF2_ETH_GMAC
>>            by the BCM_SF2_ETH driver.
>>            Say Y to any bcmcygnus based platforms.
>>
>> +config BCM6348_ETH
>> +       bool "BCM6348 EMAC support"
>> +       depends on DM_ETH && ARCH_BMIPS
>> +       select DMA
>> +       select DMA_CHANNELS
>> +       select MII
>> +       select PHYLIB
>> +       help
>> +         This driver supports the BCM6348 Ethernet MAC.
>> +
>>   config DWC_ETH_QOS
>>          bool "Synopsys DWC Ethernet QOS device support"
>>          depends on DM_ETH
>> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
>> index ac5443c752..282adbc775 100644
>> --- a/drivers/net/Makefile
>> +++ b/drivers/net/Makefile
>> @@ -8,6 +8,7 @@
>>   obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
>>   obj-$(CONFIG_AG7XXX) += ag7xxx.o
>>   obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
>> +obj-$(CONFIG_BCM6348_ETH) += bcm6348-eth.o
>>   obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
>>   obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
>>   obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
>> diff --git a/drivers/net/bcm6348-eth.c b/drivers/net/bcm6348-eth.c
>> new file mode 100644
>> index 0000000000..43518f7b2d
>> --- /dev/null
>> +++ b/drivers/net/bcm6348-eth.c
>> @@ -0,0 +1,575 @@
>> +/*
>> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
>> + *
>> + * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
>> + *     Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
>> + *
>> + * SPDX-License-Identifier: GPL-2.0+
>> + */
>> +
>> +#include <common.h>
>> +#include <clk.h>
>> +#include <dm.h>
>> +#include <dma.h>
>> +#include <miiphy.h>
>> +#include <net.h>
>> +#include <phy.h>
>> +#include <reset.h>
>> +#include <wait_bit.h>
>> +#include <asm/io.h>
>> +
>> +#define ETH_RX_DESC                    PKTBUFSRX
>> +#define ETH_MAX_MTU_SIZE               1518
>> +#define ETH_TIMEOUT                    100
>> +#define ETH_TX_WATERMARK               32
>> +
>> +/* ETH Receiver Configuration register */
>> +#define ETH_RXCFG_REG                  0x00
>> +#define ETH_RXCFG_ENFLOW_SHIFT         5
>> +#define ETH_RXCFG_ENFLOW_MASK          (1 << ETH_RXCFG_ENFLOW_SHIFT)
>> +
>> +/* ETH Receive Maximum Length register */
>> +#define ETH_RXMAXLEN_REG               0x04
>> +#define ETH_RXMAXLEN_SHIFT             0
>> +#define ETH_RXMAXLEN_MASK              (0x7ff << ETH_RXMAXLEN_SHIFT)
>> +
>> +/* ETH Transmit Maximum Length register */
>> +#define ETH_TXMAXLEN_REG               0x08
>> +#define ETH_TXMAXLEN_SHIFT             0
>> +#define ETH_TXMAXLEN_MASK              (0x7ff << ETH_TXMAXLEN_SHIFT)
>> +
>> +/* MII Status/Control register */
>> +#define MII_SC_REG                     0x10
>> +#define MII_SC_MDCFREQDIV_SHIFT                0
>> +#define MII_SC_MDCFREQDIV_MASK         (0x7f << MII_SC_MDCFREQDIV_SHIFT)
>> +#define MII_SC_PREAMBLE_EN_SHIFT       7
>> +#define MII_SC_PREAMBLE_EN_MASK                (1 << MII_SC_PREAMBLE_EN_SHIFT)
>> +
>> +/* MII Data register */
>> +#define MII_DAT_REG                    0x14
>> +#define MII_DAT_DATA_SHIFT             0
>> +#define MII_DAT_DATA_MASK              (0xffff << MII_DAT_DATA_SHIFT)
>> +#define MII_DAT_TA_SHIFT               16
>> +#define MII_DAT_TA_MASK                        (0x3 << MII_DAT_TA_SHIFT)
>> +#define MII_DAT_REG_SHIFT              18
>> +#define MII_DAT_REG_MASK               (0x1f << MII_DAT_REG_SHIFT)
>> +#define MII_DAT_PHY_SHIFT              23
>> +#define MII_DAT_PHY_MASK               (0x1f << MII_DAT_PHY_SHIFT)
>> +#define MII_DAT_OP_SHIFT               28
>> +#define MII_DAT_OP_WRITE               (0x5 << MII_DAT_OP_SHIFT)
>> +#define MII_DAT_OP_READ                        (0x6 << MII_DAT_OP_SHIFT)
>> +
>> +/* ETH Interrupts Mask register */
>> +#define ETH_IRMASK_REG                 0x18
>> +
>> +/* ETH Interrupts register */
>> +#define ETH_IR_REG                     0x1c
>> +#define ETH_IR_MII_SHIFT               0
>> +#define ETH_IR_MII_MASK                        (1 << ETH_IR_MII_SHIFT)
>> +
>> +/* ETH Control register */
>> +#define ETH_CTL_REG                    0x2c
>> +#define ETH_CTL_ENABLE_SHIFT           0
>> +#define ETH_CTL_ENABLE_MASK            (1 << ETH_CTL_ENABLE_SHIFT)
>> +#define ETH_CTL_DISABLE_SHIFT          1
>> +#define ETH_CTL_DISABLE_MASK           (1 << ETH_CTL_DISABLE_SHIFT)
>> +#define ETH_CTL_RESET_SHIFT            2
>> +#define ETH_CTL_RESET_MASK             (1 << ETH_CTL_RESET_SHIFT)
>> +#define ETH_CTL_EPHY_SHIFT             3
>> +#define ETH_CTL_EPHY_MASK              (1 << ETH_CTL_EPHY_SHIFT)
>> +
>> +/* ETH Transmit Control register */
>> +#define ETH_TXCTL_REG                  0x30
>> +#define ETH_TXCTL_FD_SHIFT             0
>> +#define ETH_TXCTL_FD_MASK              (1 << ETH_TXCTL_FD_SHIFT)
>> +
>> +/* ETH Transmit Watermask register */
>> +#define ETH_TXWMARK_REG                        0x34
>> +#define ETH_TXWMARK_WM_SHIFT           0
>> +#define ETH_TXWMARK_WM_MASK            (0x3f << ETH_TXWMARK_WM_SHIFT)
>> +
>> +/* MIB Control register */
>> +#define MIB_CTL_REG                    0x38
>> +#define MIB_CTL_RDCLEAR_SHIFT          0
>> +#define MIB_CTL_RDCLEAR_MASK           (1 << MIB_CTL_RDCLEAR_SHIFT)
>> +
>> +/* ETH Perfect Match registers */
>> +#define ETH_PM_CNT                     4
>> +#define ETH_PML_REG(x)                 (0x58 + (x) * 0x8)
>> +#define ETH_PMH_REG(x)                 (0x5c + (x) * 0x8)
>> +#define ETH_PMH_VALID_SHIFT            16
>> +#define ETH_PMH_VALID_MASK             (1 << ETH_PMH_VALID_SHIFT)
>> +
>> +/* MIB Counters registers */
>> +#define MIB_REG_CNT                    55
>> +#define MIB_REG(x)                     (0x200 + (x) * 4)
>> +
>> +/* ETH data */
>> +struct bcm6348_eth_priv {
>> +       void __iomem *base;
>> +       /* RX */
>> +       uint8_t rx_desc;
>> +       uint8_t rx_pend;
>> +       int rx_ret[ETH_RX_DESC];
>> +       /* DMA */
>> +       struct dma rx_dma;
>> +       struct dma tx_dma;
>> +       /* PHY */
>> +       int phy_id;
>> +       struct phy_device *phy_dev;
>> +};
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +static void bcm6348_eth_mac_disable(struct bcm6348_eth_priv *priv)
>> +{
>> +       /* disable emac */
>> +       clrsetbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK,
>> +                       ETH_CTL_DISABLE_MASK);
>> +
>> +       /* wait until emac is disabled */
>> +       if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
>> +                             ETH_CTL_DISABLE_MASK, false,
>> +                             ETH_TIMEOUT, false))
>> +               pr_err("error disabling emac\n");
>> +}
>> +
>> +static void bcm6348_eth_mac_enable(struct bcm6348_eth_priv *priv)
>> +{
>> +       setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK);
>> +}
>> +
>> +static void bcm6348_eth_mac_reset(struct bcm6348_eth_priv *priv)
>> +{
>> +       /* reset emac */
>> +       writel_be(ETH_CTL_RESET_MASK, priv->base + ETH_CTL_REG);
>> +       wmb();
>> +
>> +       /* wait until emac is reset */
>> +       if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
>> +                             ETH_CTL_RESET_MASK, false,
>> +                             ETH_TIMEOUT, false))
>> +               pr_err("error resetting emac\n");
>> +}
>> +
>> +static int bcm6348_eth_free_pkt(struct udevice *dev, uchar *packet, int len)
>> +{
>> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
>> +
>> +       /* sanity check */
>> +       if (packet != net_rx_packets[priv->rx_pend]) {
>> +               pr_err("rx_pend %d: packet is not matched,\n", priv->rx_pend);
>> +               return -EAGAIN;
>> +       }
>> +
>> +       /* free pending packet */
>> +       priv->rx_ret[priv->rx_pend] = 0;
>> +       priv->rx_pend = (priv->rx_pend + 1) % ETH_RX_DESC;
>> +
>> +       return 0;
>> +}
>> +
>> +static int _bcm6348_eth_recv(struct bcm6348_eth_priv *priv)
>> +{
>> +       uint8_t pkt = priv->rx_desc;
>> +
>> +       /* check if packet is free */
>> +       if (priv->rx_ret[pkt] > 0)
>> +               return -EAGAIN;
>> +
>> +       /* try to receive a new packet */
>> +       priv->rx_ret[pkt] = dma_receive(&priv->rx_dma,
>> +                                       (void **)&net_rx_packets[pkt]);
>> +       if (priv->rx_ret[pkt] > 0)
>> +               priv->rx_desc = (priv->rx_desc + 1) % ETH_RX_DESC;
>> +
>> +       return priv->rx_ret[pkt];
>> +}
>> +
>> +static int bcm6348_eth_recv(struct udevice *dev, int flags, uchar **packetp)
>> +{
>> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
>> +       uint8_t pkt_cnt = 0;
>> +       int ret;
>> +
>> +       /* try to receive packets */
>> +       while (_bcm6348_eth_recv(priv) > 0)
>> +               pkt_cnt++;
>> +
>> +       if (pkt_cnt)
>> +               debug("%s: received %u packet(s)\n", __func__, pkt_cnt);
>> +
>> +       /* return current packet */
>> +       ret = priv->rx_ret[priv->rx_pend];
>> +       if (ret > 0)
>> +               *packetp = net_rx_packets[priv->rx_pend];
>> +
>> +       return ret;
>> +}
>> +
>> +static int bcm6348_eth_send(struct udevice *dev, void *packet, int length)
>> +{
>> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
>> +
>> +       /* reset dma rx channel */
>> +       dma_disable(&priv->rx_dma);
>> +       dma_enable(&priv->rx_dma);
> Why. Please include reasoning in the comment.
For what I've seen flow control is a bit tricky on this dma controller 
and when you don't process a received packet in a short period of time, 
it may get into a an state where no new packets are correctly received.
However, resetting the dma channel here prevents that from hapenning.
>
>> +
>> +       return dma_send(&priv->tx_dma, (void *)packet, length);
>> +}
>> +
>> +static int bcm6348_eth_adjust_link(struct udevice *dev,
>> +                                  struct phy_device *phydev)
>> +{
>> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
>> +
>> +       /* mac duplex parameters */
>> +       if (phydev->duplex)
>> +               setbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
>> +       else
>> +               clrbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
>> +
>> +       /* rx flow control (pause frame handling) */
>> +       if (phydev->pause)
>> +               setbits_be32(priv->base + ETH_RXCFG_REG,
>> +                            ETH_RXCFG_ENFLOW_MASK);
>> +       else
>> +               clrbits_be32(priv->base + ETH_RXCFG_REG,
>> +                            ETH_RXCFG_ENFLOW_MASK);
>> +
>> +       return 0;
>> +}
>> +
>> +static int bcm6348_eth_start(struct udevice *dev)
>> +{
>> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
>> +       int ret, i;
>> +
>> +       priv->rx_desc = 0;
>> +       priv->rx_pend = 0;
>> +       for (i = 0; i < ETH_RX_DESC; i++)
>> +               priv->rx_ret[i] = 0;
>> +
>> +       /* enable dma rx channel */
>> +       dma_enable(&priv->rx_dma);
>> +
>> +       /* enable dma tx channel */
>> +       dma_enable(&priv->tx_dma);
>> +
>> +       ret = phy_startup(priv->phy_dev);
>> +       if (ret) {
>> +               pr_err("could not initialize phy\n");
>> +               return ret;
>> +       }
>> +
>> +       if (!priv->phy_dev->link) {
>> +               pr_err("no phy link\n");
>> +               return -EIO;
>> +       }
>> +
>> +       bcm6348_eth_adjust_link(dev, priv->phy_dev);
>> +
>> +       /* zero mib counters */
>> +       for (i = 0; i < MIB_REG_CNT; i++)
>> +               writel_be(0, MIB_REG(i));
>> +
>> +       /* enable rx flow control */
>> +       setbits_be32(priv->base + ETH_RXCFG_REG, ETH_RXCFG_ENFLOW_MASK);
>> +
>> +       /* set max rx/tx length */
>> +       writel_be((ETH_MAX_MTU_SIZE << ETH_RXMAXLEN_SHIFT) &
>> +                 ETH_RXMAXLEN_MASK, priv->base + ETH_RXMAXLEN_REG);
>> +       writel_be((ETH_MAX_MTU_SIZE << ETH_TXMAXLEN_SHIFT) &
>> +                  ETH_TXMAXLEN_MASK, priv->base + ETH_TXMAXLEN_REG);
>> +
>> +       /* set correct transmit fifo watermark */
>> +       writel_be((ETH_TX_WATERMARK << ETH_TXWMARK_WM_SHIFT) &
>> +                 ETH_TXWMARK_WM_MASK, priv->base + ETH_TXWMARK_REG);
>> +
>> +       /* enable emac */
>> +       bcm6348_eth_mac_enable(priv);
>> +
>> +       /* clear interrupts */
>> +       writel_be(0, priv->base + ETH_IRMASK_REG);
>> +
>> +       return 0;
>> +}
>> +
>> +static void bcm6348_eth_stop(struct udevice *dev)
>> +{
>> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
>> +
>> +       /* disable dma rx channel */
>> +       dma_disable(&priv->rx_dma);
>> +
>> +       /* disable dma tx channel */
>> +       dma_disable(&priv->tx_dma);
>> +
>> +       /* disable emac */
>> +       bcm6348_eth_mac_disable(priv);
>> +}
>> +
>> +static int bcm6348_eth_write_hwaddr(struct udevice *dev)
>> +{
>> +       struct eth_pdata *pdata = dev_get_platdata(dev);
>> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
>> +       bool running = false;
>> +
>> +       /* check if emac is running */
>> +       if (readl_be(priv->base + ETH_CTL_REG) & ETH_CTL_ENABLE_MASK)
>> +               running = true;
>> +
>> +       /* disable emac */
>> +       if (running)
>> +               bcm6348_eth_mac_disable(priv);
>> +
>> +       /* set mac address */
>> +       writel_be((pdata->enetaddr[2] << 24) | (pdata->enetaddr[3]) << 16 |
>> +                 (pdata->enetaddr[4]) << 8 | (pdata->enetaddr[5]),
>> +                 priv->base + ETH_PML_REG(0));
>> +       writel_be((pdata->enetaddr[1]) | (pdata->enetaddr[0] << 8) |
>> +                 ETH_PMH_VALID_MASK, priv->base + ETH_PMH_REG(0));
>> +
>> +       /* enable emac */
>> +       if (running)
>> +               bcm6348_eth_mac_enable(priv);
>> +
>> +       return 0;
>> +}
>> +
>> +static const struct eth_ops bcm6348_eth_ops = {
>> +       .free_pkt = bcm6348_eth_free_pkt,
>> +       .recv = bcm6348_eth_recv,
>> +       .send = bcm6348_eth_send,
>> +       .start = bcm6348_eth_start,
>> +       .stop = bcm6348_eth_stop,
>> +       .write_hwaddr = bcm6348_eth_write_hwaddr,
>> +};
>> +
>> +static const struct udevice_id bcm6348_eth_ids[] = {
>> +       { .compatible = "brcm,bcm6348-enet", },
>> +       { /* sentinel */ }
>> +};
>> +
>> +static int bcm6348_mdio_op(void __iomem *base, uint32_t data)
>> +{
>> +       /* make sure mii interrupt status is cleared */
>> +       writel_be(ETH_IR_MII_MASK, base + ETH_IR_REG);
>> +
>> +       /* issue mii op */
>> +       writel_be(data, base + MII_DAT_REG);
>> +
>> +       /* wait until emac is disabled */
>> +       return wait_for_bit_be32(base + ETH_IR_REG,
>> +                                ETH_IR_MII_MASK, true,
>> +                                ETH_TIMEOUT, false);
>> +}
>> +
>> +static int bcm6348_mdio_read(struct mii_dev *bus, int addr, int devaddr,
>> +                            int reg)
>> +{
>> +       void __iomem *base = bus->priv;
>> +       uint32_t val;
>> +
>> +       val = MII_DAT_OP_READ;
>> +       val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
>> +       val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
>> +       val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
>> +
>> +       if (bcm6348_mdio_op(base, val)) {
>> +               pr_err("%s: timeout\n", __func__);
>> +               return -EINVAL;
>> +       }
>> +
>> +       val = readl_be(base + MII_DAT_REG) & MII_DAT_DATA_MASK;
>> +       val >>= MII_DAT_DATA_SHIFT;
>> +
>> +       return val;
>> +}
>> +
>> +static int bcm6348_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
>> +                             int reg, u16 value)
>> +{
>> +       void __iomem *base = bus->priv;
>> +       uint32_t val;
>> +
>> +       val = MII_DAT_OP_WRITE;
>> +       val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
>> +       val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
>> +       val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
>> +       val |= (value << MII_DAT_DATA_SHIFT) & MII_DAT_DATA_MASK;
>> +
>> +       if (bcm6348_mdio_op(base, val)) {
>> +               pr_err("%s: timeout\n", __func__);
>> +               return -EINVAL;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int bcm6348_mdio_init(const char *name, void __iomem *base)
>> +{
>> +       struct mii_dev *bus;
>> +
>> +       bus = mdio_alloc();
>> +       if (!bus) {
>> +               pr_err("%s: failed to allocate MDIO bus\n", __func__);
>> +               return -ENOMEM;
>> +       }
>> +
>> +       bus->read = bcm6348_mdio_read;
>> +       bus->write = bcm6348_mdio_write;
>> +       bus->priv = base;
>> +       snprintf(bus->name, sizeof(bus->name), "%s", name);
>> +
>> +       return mdio_register(bus);
>> +}
>> +
>> +static int bcm6348_phy_init(struct udevice *dev)
>> +{
>> +       struct eth_pdata *pdata = dev_get_platdata(dev);
>> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
>> +       struct mii_dev *bus;
>> +
>> +       /* get mii bus */
>> +       bus = miiphy_get_dev_by_name(dev->name);
>> +
>> +       /* phy connect */
>> +       priv->phy_dev = phy_connect(bus, priv->phy_id, dev,
>> +                                   pdata->phy_interface);
>> +       if (!priv->phy_dev) {
>> +               pr_err("%s: no phy device\n", __func__);
>> +               return -ENODEV;
>> +       }
>> +
>> +       priv->phy_dev->supported = (SUPPORTED_10baseT_Half |
>> +                                   SUPPORTED_10baseT_Full |
>> +                                   SUPPORTED_100baseT_Half |
>> +                                   SUPPORTED_100baseT_Full |
>> +                                   SUPPORTED_Autoneg |
>> +                                   SUPPORTED_Pause |
>> +                                   SUPPORTED_MII);
>> +       priv->phy_dev->advertising = priv->phy_dev->supported;
>> +
>> +       /* phy config */
>> +       phy_config(priv->phy_dev);
>> +
>> +       return 0;
>> +}
>> +
>> +static int bcm6348_eth_probe(struct udevice *dev)
>> +{
>> +       struct eth_pdata *pdata = dev_get_platdata(dev);
>> +       struct bcm6348_eth_priv *priv = dev_get_priv(dev);
>> +       void *blob = (void *)gd->fdt_blob;
>> +       int node = dev_of_offset(dev);
>> +       const char *phy_mode;
>> +       fdt_addr_t addr;
>> +       int phy_node, ret, i;
>> +
>> +       /* get base address */
>> +       addr = devfdt_get_addr(dev);
>> +       if (addr == FDT_ADDR_T_NONE)
>> +               return -EINVAL;
>> +
>> +       /* get phy mode */
>> +       pdata->phy_interface = PHY_INTERFACE_MODE_NONE;
>> +       phy_mode = fdt_getprop(blob, node, "phy-mode", NULL);
>> +       if (phy_mode)
>> +               pdata->phy_interface = phy_get_interface_by_name(phy_mode);
>> +       if (pdata->phy_interface == PHY_INTERFACE_MODE_NONE)
>> +               return -ENODEV;
>> +
>> +       /* get phy */
>> +       phy_node = fdtdec_lookup_phandle(blob, node, "phy");
>> +       if (phy_node >= 0)
>> +               priv->phy_id = fdtdec_get_int(blob, phy_node, "reg", -1);
>> +       else
>> +               return -EINVAL;
>> +
>> +       /* get dma channels */
>> +       ret = dma_get_by_name(dev, "tx", &priv->tx_dma);
>> +       if (ret)
>> +               return -EINVAL;
>> +
>> +       ret = dma_get_by_name(dev, "rx", &priv->rx_dma);
>> +       if (ret)
>> +               return -EINVAL;
>> +
>> +       /* try to enable clocks */
>> +       for (i = 0; ; i++) {
>> +               struct clk clk;
>> +               int ret;
>> +
>> +               ret = clk_get_by_index(dev, i, &clk);
>> +               if (ret < 0)
>> +                       break;
>> +               if (clk_enable(&clk))
>> +                       pr_err("failed to enable clock %d\n", i);
>> +               clk_free(&clk);
>> +       }
>> +
>> +       /* try to perform resets */
>> +       for (i = 0; ; i++) {
>> +               struct reset_ctl reset;
>> +               int ret;
>> +
>> +               ret = reset_get_by_index(dev, i, &reset);
>> +               if (ret < 0)
>> +                       break;
>> +               if (reset_deassert(&reset))
>> +                       pr_err("failed to deassert reset %d\n", i);
>> +               reset_free(&reset);
>> +       }
>> +
>> +       /* get base addr */
>> +       priv->base = ioremap(addr, 0);
>> +       pdata->iobase = (phys_addr_t) priv->base;
>> +
>> +       /* disable emac */
>> +       bcm6348_eth_mac_disable(priv);
>> +
>> +       /* reset emac */
>> +       bcm6348_eth_mac_reset(priv);
>> +
>> +       /* select correct mii interface */
>> +       if (pdata->phy_interface == PHY_INTERFACE_MODE_INTERNAL)
>> +               clrbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
>> +       else
>> +               setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
>> +
>> +       /* turn on mdc clock */
>> +       writel_be((0x1f << MII_SC_MDCFREQDIV_SHIFT) |
>> +                 MII_SC_PREAMBLE_EN_MASK, priv->base + MII_SC_REG);
>> +
>> +       /* set mib counters to not clear when read */
>> +       clrbits_be32(priv->base + MIB_CTL_REG, MIB_CTL_RDCLEAR_MASK);
>> +
>> +       /* initialize perfect match registers */
>> +       for (i = 0; i < ETH_PM_CNT; i++) {
>> +               writel_be(0, priv->base + ETH_PML_REG(i));
>> +               writel_be(0, priv->base + ETH_PMH_REG(i));
>> +       }
>> +
>> +       /* init mii bus */
>> +       ret = bcm6348_mdio_init(dev->name, priv->base);
>> +       if (ret)
>> +               return ret;
>> +
>> +       /* init phy */
>> +       ret = bcm6348_phy_init(dev);
>> +       if (ret)
>> +               return ret;
>> +
>> +       return 0;
>> +}
>> +
>> +U_BOOT_DRIVER(bcm6348_eth) = {
>> +       .name = "bcm6348_eth",
>> +       .id = UCLASS_ETH,
>> +       .of_match = bcm6348_eth_ids,
>> +       .ops = &bcm6348_eth_ops,
>> +       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
>> +       .priv_auto_alloc_size = sizeof(struct bcm6348_eth_priv),
>> +       .probe = bcm6348_eth_probe,
>> +};
>> diff --git a/include/configs/bmips_common.h b/include/configs/bmips_common.h
>> index 38bf7a272b..eb66512f67 100644
>> --- a/include/configs/bmips_common.h
>> +++ b/include/configs/bmips_common.h
>> @@ -7,6 +7,9 @@
>>   #ifndef __CONFIG_BMIPS_COMMON_H
>>   #define __CONFIG_BMIPS_COMMON_H
>>
>> +/* ETH */
>> +#define CONFIG_PHY_RESET_DELAY         20
>> +
>>   /* UART */
>>   #define CONFIG_SYS_BAUDRATE_TABLE      { 9600, 19200, 38400, 57600, 115200, \
>>                                            230400, 500000, 1500000 }
>> @@ -17,7 +20,7 @@
>>
>>   /* Memory usage */
>>   #define CONFIG_SYS_MAXARGS             24
>> -#define CONFIG_SYS_MALLOC_LEN          (1024 * 1024)
>> +#define CONFIG_SYS_MALLOC_LEN          (2 * 1024 * 1024)
>>   #define CONFIG_SYS_BOOTPARAMS_LEN      (128 * 1024)
>>   #define CONFIG_SYS_CBSIZE              512
>>
>> --
>> 2.11.0
>>
>> _______________________________________________
>> U-Boot mailing list
>> U-Boot at lists.denx.de
>> https://lists.denx.de/listinfo/u-boot
~Álvaro.

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 07/15] phy: add support for internal phys
  2018-03-08 19:38       ` Álvaro Fernández Rojas
@ 2018-03-08 20:11         ` Joe Hershberger
  0 siblings, 0 replies; 106+ messages in thread
From: Joe Hershberger @ 2018-03-08 20:11 UTC (permalink / raw)
  To: u-boot

On Thu, Mar 8, 2018 at 1:38 PM, Álvaro Fernández Rojas
<noltari@gmail.com> wrote:
> Hi Joe,
>
> El 07/03/2018 a las 21:28, Joe Hershberger escribió:
>>
>> On Mon, Mar 5, 2018 at 2:05 PM, Álvaro Fernández Rojas
>> <noltari@gmail.com> wrote:
>>>
>>> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
>>> ---
>>>   v5: no changes
>>>   v4: no changes
>>>   v3: no changes
>>>   v2: no changes
>>>
>>>   include/phy.h | 2 ++
>>>   1 file changed, 2 insertions(+)
>>>
>>> diff --git a/include/phy.h b/include/phy.h
>>> index 0543ec10c2..8f3e53db01 100644
>>> --- a/include/phy.h
>>> +++ b/include/phy.h
>>> @@ -50,6 +50,7 @@
>>>
>>>
>>>   typedef enum {
>>> +       PHY_INTERFACE_MODE_INTERNAL,
>>
>> In Linux this is handled as a flag instead of a different mode. It
>> seems we should do it the same way.
>
> Not really, in Linux this is handled as both:
> - As a flag (https://elixir.bootlin.com/linux/latest/ident/PHY_IS_INTERNAL):
> https://github.com/torvalds/linux/blob/master/include/linux/phy.h#L61
> https://github.com/torvalds/linux/blob/master/drivers/net/phy/phy_device.c#L1792
> https://github.com/torvalds/linux/blob/master/include/linux/phy.h#L832
> - As a mode
> (https://elixir.bootlin.com/linux/latest/ident/PHY_INTERFACE_MODE_INTERNAL):
> https://github.com/torvalds/linux/blob/master/include/linux/phy.h#L68
> https://github.com/torvalds/linux/blob/master/include/linux/phy.h#L119
>

OK, I was looking at an older kernel where there was only the flag.

Acked-by: Joe Hershberger <joe.hershberger@ni.com>

>>
>>>          PHY_INTERFACE_MODE_MII,
>>>          PHY_INTERFACE_MODE_GMII,
>>>          PHY_INTERFACE_MODE_SGMII,
>>> @@ -72,6 +73,7 @@ typedef enum {
>>>   } phy_interface_t;
>>>
>>>   static const char *phy_interface_strings[] = {
>>> +       [PHY_INTERFACE_MODE_INTERNAL]           = "internal",
>>>          [PHY_INTERFACE_MODE_MII]                = "mii",
>>>          [PHY_INTERFACE_MODE_GMII]               = "gmii",
>>>          [PHY_INTERFACE_MODE_SGMII]              = "sgmii",
>>> --
>>> 2.11.0
>>>
>>> _______________________________________________
>>> U-Boot mailing list
>>> U-Boot at lists.denx.de
>>> https://lists.denx.de/listinfo/u-boot
>
> ~Álvaro.
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 02/15] dma: add channels support
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 02/15] dma: add channels support Álvaro Fernández Rojas
  2018-03-07 21:27     ` Joe Hershberger
@ 2018-03-08 23:07     ` Grygorii Strashko
  2018-03-09 18:42       ` Álvaro Fernández Rojas
  2018-03-11 19:14     ` Daniel Schwierzeck
  2 siblings, 1 reply; 106+ messages in thread
From: Grygorii Strashko @ 2018-03-08 23:07 UTC (permalink / raw)
  To: u-boot

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 <noltari@gmail.com>
> Reviewed-by: Simon Glass <sjg@chromium.org>
> ---
>   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, <www.ti.com>
> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
> + * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
>    *
>    * SPDX-License-Identifier:     GPL-2.0+
>    */
> @@ -8,6 +9,9 @@
>   #ifndef _DMA_H_
>   #define _DMA_H_
>   
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +
>   /*
>    * 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 provider. A provider will
> + * often implement multiple separate DMAs, since the hardware it manages
> + * often has this capability. dma_uclass.h describes the interface which
> + * DMA providers must implement.
> + *
> + * DMA consumers/clients are the HW modules driven by the DMA channels. This
> + * header file describes the API used by drivers for those HW modules.
> + */
> +
> +struct udevice;
> +
> +/**
> + * struct dma - A handle to (allowing control of) a single DMA.
> + *
> + * Clients provide storage for DMA handles. The content of the structure is
> + * managed solely by the DMA API and DMA drivers. A DMA struct is
> + * initialized by "get"ing the DMA struct. The DMA struct is passed to all
> + * other DMA APIs to identify which DMA channel to operate upon.
> + *
> + * @dev: The device which implements the DMA channel.
> + * @id: The DMA channel ID within the provider.
> + *
> + * Currently, the DMA API assumes that a single integer ID is enough to
> + * identify and configure any DMA channel for any DMA provider. If this
> + * assumption becomes invalid in the future, the struct could be expanded to
> + * either (a) add more fields to allow DMA providers to store additional
> + * information, or (b) replace the id field with an opaque pointer, which the
> + * provider would dynamically allocated during its .of_xlate op, and process
> + * during is .request op. This may require the addition of an extra op to clean
> + * up the allocation.
> + */
> +struct dma {
> +	struct udevice *dev;
> +	/*
> +	 * Written by of_xlate. We assume a single id is enough for now. In the
> +	 * future, we might add more fields here.
> +	 */
> +	unsigned long id;
> +};
> +
> +# if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DMA)
> +struct phandle_1_arg;
> +int dma_get_by_index_platdata(struct udevice *dev, int index,
> +			      struct phandle_1_arg *cells, struct dma *dma);
> +
> +/**
> + * dma_get_by_index - Get/request a DMA by integer index.
> + *
> + * This looks up and requests a DMA. The index is relative to the client
> + * device; each device is assumed to have n DMAs associated with it somehow,
> + * and this function finds and requests one of them. The mapping of client
> + * device DMA indices to provider DMAs may be via device-tree properties,
> + * board-provided mapping tables, or some other mechanism.
> + *
> + * @dev:	The client device.
> + * @index:	The index of the DMA to request, within the client's list of
> + *		DMA channels.
> + * @dma:	A pointer to a DMA struct to initialize.
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_get_by_index(struct udevice *dev, int index, struct dma *dma);
> +
> +/**
> + * dma_get_by_name - Get/request a DMA by name.
> + *
> + * This looks up and requests a DMA. The name is relative to the client
> + * device; each device is assumed to have n DMAs associated with it somehow,
> + * and this function finds and requests one of them. The mapping of client
> + * device DMA names to provider DMAs may be via device-tree properties,
> + * board-provided mapping tables, or some other mechanism.
> + *
> + * @dev:	The client device.
> + * @name:	The name of the DMA to request, within the client's list of
> + *		DMA channels.
> + * @dma:	A pointer to a DMA struct to initialize.
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma);
> +# else
> +static inline int dma_get_by_index(struct udevice *dev, int index,
> +				   struct dma *dma)
> +{
> +	return -ENOSYS;
> +}
> +
> +static inline int dma_get_by_name(struct udevice *dev, const char *name,
> +			   struct dma *dma)
> +{
> +	return -ENOSYS;
> +}
> +# endif
> +
> +/**
> + * dma_request - Request a DMA by provider-specific ID.
> + *
> + * This requests a DMA using a provider-specific ID. Generally, this function
> + * should not be used, since dma_get_by_index/name() provide an interface that
> + * better separates clients from intimate knowledge of DMA providers.
> + * However, this function may be useful in core SoC-specific code.
> + *
> + * @dev: The DMA provider device.
> + * @dma: A pointer to a DMA struct to initialize. The caller must
> + *	 have already initialized any field in this struct which the
> + *	 DMA provider uses to identify the DMA channel.
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_request(struct udevice *dev, struct dma *dma);
> +
> +/**
> + * dma_free - Free a previously requested DMA.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_free(struct dma *dma);
> +
> +/**
> + * dma_enable() - Enable (turn on) a DMA channel.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @return zero on success, or -ve error code.
> + */
> +int dma_enable(struct dma *dma);
> +
> +/**
> + * dma_disable() - Disable (turn off) a DMA channel.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @return zero on success, or -ve error code.
> + */
> +int dma_disable(struct dma *dma);
> +
> +/**
> + * dma_receive() - Receive a DMA transfer.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @dst: The destination pointer.
> + * @return zero on success, or -ve error code.
> + */
> +int dma_receive(struct dma *dma, void **dst);
> +
> +/**
> + * dma_send() - Send a DMA transfer.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @src: The source pointer.
> + * @len: Length of the data to be sent (number of bytes).
> + * @return zero on success, or -ve error code.
> + */
> +int dma_send(struct dma *dma, void *src, size_t len);
> +#endif /* CONFIG_DMA_CHANNELS */
> +
>   /*
>    * dma_get_device - get a DMA device which supports transfer
>    * type of transfer_type
> 

-- 
regards,
-grygorii

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 02/15] dma: add channels support
  2018-03-08 23:07     ` Grygorii Strashko
@ 2018-03-09 18:42       ` Álvaro Fernández Rojas
  0 siblings, 0 replies; 106+ messages in thread
From: Álvaro Fernández Rojas @ 2018-03-09 18:42 UTC (permalink / raw)
  To: u-boot

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 <noltari@gmail.com>
>> Reviewed-by: Simon Glass <sjg@chromium.org>
>> ---
>>    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, <www.ti.com>
>> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
>> + * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
>> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
>>     *
>>     * SPDX-License-Identifier:     GPL-2.0+
>>     */
>> @@ -8,6 +9,9 @@
>>    #ifndef _DMA_H_
>>    #define _DMA_H_
>>    
>> +#include <linux/errno.h>
>> +#include <linux/types.h>
>> +
>>    /*
>>     * 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 provider. A provider will
>> + * often implement multiple separate DMAs, since the hardware it manages
>> + * often has this capability. dma_uclass.h describes the interface which
>> + * DMA providers must implement.
>> + *
>> + * DMA consumers/clients are the HW modules driven by the DMA channels. This
>> + * header file describes the API used by drivers for those HW modules.
>> + */
>> +
>> +struct udevice;
>> +
>> +/**
>> + * struct dma - A handle to (allowing control of) a single DMA.
>> + *
>> + * Clients provide storage for DMA handles. The content of the structure is
>> + * managed solely by the DMA API and DMA drivers. A DMA struct is
>> + * initialized by "get"ing the DMA struct. The DMA struct is passed to all
>> + * other DMA APIs to identify which DMA channel to operate upon.
>> + *
>> + * @dev: The device which implements the DMA channel.
>> + * @id: The DMA channel ID within the provider.
>> + *
>> + * Currently, the DMA API assumes that a single integer ID is enough to
>> + * identify and configure any DMA channel for any DMA provider. If this
>> + * assumption becomes invalid in the future, the struct could be expanded to
>> + * either (a) add more fields to allow DMA providers to store additional
>> + * information, or (b) replace the id field with an opaque pointer, which the
>> + * provider would dynamically allocated during its .of_xlate op, and process
>> + * during is .request op. This may require the addition of an extra op to clean
>> + * up the allocation.
>> + */
>> +struct dma {
>> +	struct udevice *dev;
>> +	/*
>> +	 * Written by of_xlate. We assume a single id is enough for now. In the
>> +	 * future, we might add more fields here.
>> +	 */
>> +	unsigned long id;
>> +};
>> +
>> +# if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DMA)
>> +struct phandle_1_arg;
>> +int dma_get_by_index_platdata(struct udevice *dev, int index,
>> +			      struct phandle_1_arg *cells, struct dma *dma);
>> +
>> +/**
>> + * dma_get_by_index - Get/request a DMA by integer index.
>> + *
>> + * This looks up and requests a DMA. The index is relative to the client
>> + * device; each device is assumed to have n DMAs associated with it somehow,
>> + * and this function finds and requests one of them. The mapping of client
>> + * device DMA indices to provider DMAs may be via device-tree properties,
>> + * board-provided mapping tables, or some other mechanism.
>> + *
>> + * @dev:	The client device.
>> + * @index:	The index of the DMA to request, within the client's list of
>> + *		DMA channels.
>> + * @dma:	A pointer to a DMA struct to initialize.
>> + * @return 0 if OK, or a negative error code.
>> + */
>> +int dma_get_by_index(struct udevice *dev, int index, struct dma *dma);
>> +
>> +/**
>> + * dma_get_by_name - Get/request a DMA by name.
>> + *
>> + * This looks up and requests a DMA. The name is relative to the client
>> + * device; each device is assumed to have n DMAs associated with it somehow,
>> + * and this function finds and requests one of them. The mapping of client
>> + * device DMA names to provider DMAs may be via device-tree properties,
>> + * board-provided mapping tables, or some other mechanism.
>> + *
>> + * @dev:	The client device.
>> + * @name:	The name of the DMA to request, within the client's list of
>> + *		DMA channels.
>> + * @dma:	A pointer to a DMA struct to initialize.
>> + * @return 0 if OK, or a negative error code.
>> + */
>> +int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma);
>> +# else
>> +static inline int dma_get_by_index(struct udevice *dev, int index,
>> +				   struct dma *dma)
>> +{
>> +	return -ENOSYS;
>> +}
>> +
>> +static inline int dma_get_by_name(struct udevice *dev, const char *name,
>> +			   struct dma *dma)
>> +{
>> +	return -ENOSYS;
>> +}
>> +# endif
>> +
>> +/**
>> + * dma_request - Request a DMA by provider-specific ID.
>> + *
>> + * This requests a DMA using a provider-specific ID. Generally, this function
>> + * should not be used, since dma_get_by_index/name() provide an interface that
>> + * better separates clients from intimate knowledge of DMA providers.
>> + * However, this function may be useful in core SoC-specific code.
>> + *
>> + * @dev: The DMA provider device.
>> + * @dma: A pointer to a DMA struct to initialize. The caller must
>> + *	 have already initialized any field in this struct which the
>> + *	 DMA provider uses to identify the DMA channel.
>> + * @return 0 if OK, or a negative error code.
>> + */
>> +int dma_request(struct udevice *dev, struct dma *dma);
>> +
>> +/**
>> + * dma_free - Free a previously requested DMA.
>> + *
>> + * @dma: A DMA struct that was previously successfully requested by
>> + *	 dma_request/get_by_*().
>> + * @return 0 if OK, or a negative error code.
>> + */
>> +int dma_free(struct dma *dma);
>> +
>> +/**
>> + * dma_enable() - Enable (turn on) a DMA channel.
>> + *
>> + * @dma: A DMA struct that was previously successfully requested by
>> + *	 dma_request/get_by_*().
>> + * @return zero on success, or -ve error code.
>> + */
>> +int dma_enable(struct dma *dma);
>> +
>> +/**
>> + * dma_disable() - Disable (turn off) a DMA channel.
>> + *
>> + * @dma: A DMA struct that was previously successfully requested by
>> + *	 dma_request/get_by_*().
>> + * @return zero on success, or -ve error code.
>> + */
>> +int dma_disable(struct dma *dma);
>> +
>> +/**
>> + * dma_receive() - Receive a DMA transfer.
>> + *
>> + * @dma: A DMA struct that was previously successfully requested by
>> + *	 dma_request/get_by_*().
>> + * @dst: The destination pointer.
>> + * @return zero on success, or -ve error code.
>> + */
>> +int dma_receive(struct dma *dma, void **dst);
>> +
>> +/**
>> + * dma_send() - Send a DMA transfer.
>> + *
>> + * @dma: A DMA struct that was previously successfully requested by
>> + *	 dma_request/get_by_*().
>> + * @src: The source pointer.
>> + * @len: Length of the data to be sent (number of bytes).
>> + * @return zero on success, or -ve error code.
>> + */
>> +int dma_send(struct dma *dma, void *src, size_t len);
>> +#endif /* CONFIG_DMA_CHANNELS */
>> +
>>    /*
>>     * dma_get_device - get a DMA device which supports transfer
>>     * type of transfer_type
>>
~Álvaro.

^ permalink raw reply	[flat|nested] 106+ messages in thread

* [U-Boot] [PATCH v5 02/15] dma: add channels support
  2018-03-05 20:05   ` [U-Boot] [PATCH v5 02/15] dma: add channels support Álvaro Fernández Rojas
  2018-03-07 21:27     ` Joe Hershberger
  2018-03-08 23:07     ` Grygorii Strashko
@ 2018-03-11 19:14     ` Daniel Schwierzeck
  2 siblings, 0 replies; 106+ messages in thread
From: Daniel Schwierzeck @ 2018-03-11 19:14 UTC (permalink / raw)
  To: u-boot

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 <noltari@gmail.com>
> Reviewed-by: Simon Glass <sjg@chromium.org>
> ---
>  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, <www.ti.com>
> - *
> - * Author: Mugunthan V N <mugunthanvnm@ti.com>
> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
> + * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
>   *
>   * SPDX-License-Identifier:     GPL-2.0+
>   */
>  
>  #include <common.h>
>  #include <dm.h>
> -#include <dm/uclass-internal.h>
> -#include <dm/device-internal.h>
> +#include <dm/read.h>
>  #include <dma-uclass.h>
> +#include <dt-structs.h>
>  #include <errno.h>
>  
>  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, &dma->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,
> +					 &args);
> +	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, &dev_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, &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);
> +	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, 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 3429f65ec4..b334adb68b 100644
> --- a/include/dma-uclass.h
> +++ b/include/dma-uclass.h
> @@ -13,6 +13,8 @@
>  
>  #include <dma.h>
>  
> +struct ofnode_phandle_args;
> +
>  /*
>   * struct dma_ops - Driver model DMA operations
>   *
> @@ -20,6 +22,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 ofnode_phandle_args *args);
> +	/**
> +	 * request - Request a translated DMA.
> +	 *
> +	 * The DMA core calls this function as the second step in
> +	 * implementing a client's dma_get_by_*() call, following a successful
> +	 * xxx_xlate() call, or as the only step in implementing a client's
> +	 * dma_request() call.
> +	 *
> +	 * @dma: The DMA struct to request; this has been filled in by
> +	 *   a previoux xxx_xlate() function call, or by the caller of
> +	 *   dma_request().
> +	 * @return 0 if OK, or a negative error code.
> +	 */
> +	int (*request)(struct dma *dma);
> +	/**
> +	 * free - Free a previously requested dma.
> +	 *
> +	 * This is the implementation of the client dma_free() API.
> +	 *
> +	 * @dma: The DMA to free.
> +	 * @return 0 if OK, or a negative error code.
> +	 */
> +	int (*free)(struct dma *dma);
> +	/**
> +	 * enable() - Enable a DMA Channel.
> +	 *
> +	 * @dma: The DMA Channel to manipulate.
> +	 * @return zero on success, or -ve error code.
> +	 */
> +	int (*enable)(struct dma *dma);
> +	/**
> +	 * disable() - Disable a DMA Channel.
> +	 *
> +	 * @dma: The DMA Channel to manipulate.
> +	 * @return zero on success, or -ve error code.
> +	 */
> +	int (*disable)(struct dma *dma);
> +	/**
> +	 * 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);
> +#endif /* CONFIG_DMA_CHANNELS */

IMHO a DMA driver should not implement receive() and send() directly as
this involves generic code like flushing/invalidating caches,
synchronous waiting on descriptor status etc. This could be better
handled by dma-uclass code than repeating it in each driver.

I think a heavily simplified design of Linux's dmaengine would help. For
instance the driver interface could be modelled with prepare_cyclic(),
prepare_memcpy() and status(). The dma-uclass can then provide an
interface for those functions as well as additional wrapper functions
like dma_is_complete(), dma_sync_wait(), dma_receive() or dma_send().

Regardless of the design, I'd like to have at least separate functions
for preparing the buffers and polling the descriptor. For instance I
have a DMA-capable NAND controller, where the DMA transfer is only
started by writing some HW registers. This must happen between preparing
the buffers and DMA descriptors and polling the descriptors until the
transaction has finished.

Could you do that?
>  	/**
>  	 * 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, <www.ti.com>
> + * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
> + * Copyright (C) 2015 Texas Instruments Incorporated <www.ti.com>
> + * Written by Mugunthan V N <mugunthanvnm@ti.com>
>   *
>   * SPDX-License-Identifier:     GPL-2.0+
>   */
> @@ -8,6 +9,9 @@
>  #ifndef _DMA_H_
>  #define _DMA_H_
>  
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +
>  /*
>   * 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 provider. A provider will
> + * often implement multiple separate DMAs, since the hardware it manages
> + * often has this capability. dma_uclass.h describes the interface which
> + * DMA providers must implement.
> + *
> + * DMA consumers/clients are the HW modules driven by the DMA channels. This
> + * header file describes the API used by drivers for those HW modules.
> + */
> +
> +struct udevice;
> +
> +/**
> + * struct dma - A handle to (allowing control of) a single DMA.
> + *
> + * Clients provide storage for DMA handles. The content of the structure is
> + * managed solely by the DMA API and DMA drivers. A DMA struct is
> + * initialized by "get"ing the DMA struct. The DMA struct is passed to all
> + * other DMA APIs to identify which DMA channel to operate upon.
> + *
> + * @dev: The device which implements the DMA channel.
> + * @id: The DMA channel ID within the provider.
> + *
> + * Currently, the DMA API assumes that a single integer ID is enough to
> + * identify and configure any DMA channel for any DMA provider. If this
> + * assumption becomes invalid in the future, the struct could be expanded to
> + * either (a) add more fields to allow DMA providers to store additional
> + * information, or (b) replace the id field with an opaque pointer, which the
> + * provider would dynamically allocated during its .of_xlate op, and process
> + * during is .request op. This may require the addition of an extra op to clean
> + * up the allocation.
> + */
> +struct dma {
> +	struct udevice *dev;
> +	/*
> +	 * Written by of_xlate. We assume a single id is enough for now. In the
> +	 * future, we might add more fields here.
> +	 */
> +	unsigned long id;
> +};
> +
> +# if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DMA)
> +struct phandle_1_arg;
> +int dma_get_by_index_platdata(struct udevice *dev, int index,
> +			      struct phandle_1_arg *cells, struct dma *dma);
> +
> +/**
> + * dma_get_by_index - Get/request a DMA by integer index.
> + *
> + * This looks up and requests a DMA. The index is relative to the client
> + * device; each device is assumed to have n DMAs associated with it somehow,
> + * and this function finds and requests one of them. The mapping of client
> + * device DMA indices to provider DMAs may be via device-tree properties,
> + * board-provided mapping tables, or some other mechanism.
> + *
> + * @dev:	The client device.
> + * @index:	The index of the DMA to request, within the client's list of
> + *		DMA channels.
> + * @dma:	A pointer to a DMA struct to initialize.
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_get_by_index(struct udevice *dev, int index, struct dma *dma);
> +
> +/**
> + * dma_get_by_name - Get/request a DMA by name.
> + *
> + * This looks up and requests a DMA. The name is relative to the client
> + * device; each device is assumed to have n DMAs associated with it somehow,
> + * and this function finds and requests one of them. The mapping of client
> + * device DMA names to provider DMAs may be via device-tree properties,
> + * board-provided mapping tables, or some other mechanism.
> + *
> + * @dev:	The client device.
> + * @name:	The name of the DMA to request, within the client's list of
> + *		DMA channels.
> + * @dma:	A pointer to a DMA struct to initialize.
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_get_by_name(struct udevice *dev, const char *name, struct dma *dma);
> +# else
> +static inline int dma_get_by_index(struct udevice *dev, int index,
> +				   struct dma *dma)
> +{
> +	return -ENOSYS;
> +}
> +
> +static inline int dma_get_by_name(struct udevice *dev, const char *name,
> +			   struct dma *dma)
> +{
> +	return -ENOSYS;
> +}
> +# endif
> +
> +/**
> + * dma_request - Request a DMA by provider-specific ID.
> + *
> + * This requests a DMA using a provider-specific ID. Generally, this function
> + * should not be used, since dma_get_by_index/name() provide an interface that
> + * better separates clients from intimate knowledge of DMA providers.
> + * However, this function may be useful in core SoC-specific code.
> + *
> + * @dev: The DMA provider device.
> + * @dma: A pointer to a DMA struct to initialize. The caller must
> + *	 have already initialized any field in this struct which the
> + *	 DMA provider uses to identify the DMA channel.
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_request(struct udevice *dev, struct dma *dma);
> +
> +/**
> + * dma_free - Free a previously requested DMA.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @return 0 if OK, or a negative error code.
> + */
> +int dma_free(struct dma *dma);
> +
> +/**
> + * dma_enable() - Enable (turn on) a DMA channel.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @return zero on success, or -ve error code.
> + */
> +int dma_enable(struct dma *dma);
> +
> +/**
> + * dma_disable() - Disable (turn off) a DMA channel.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @return zero on success, or -ve error code.
> + */
> +int dma_disable(struct dma *dma);
> +
> +/**
> + * dma_receive() - Receive a DMA transfer.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @dst: The destination pointer.
> + * @return zero on success, or -ve error code.
> + */
> +int dma_receive(struct dma *dma, void **dst);
> +
> +/**
> + * dma_send() - Send a DMA transfer.
> + *
> + * @dma: A DMA struct that was previously successfully requested by
> + *	 dma_request/get_by_*().
> + * @src: The source pointer.
> + * @len: Length of the data to be sent (number of bytes).
> + * @return zero on success, or -ve error code.
> + */
> +int dma_send(struct dma *dma, void *src, size_t len);
> +#endif /* CONFIG_DMA_CHANNELS */
> +
>  /*
>   * dma_get_device - get a DMA device which supports transfer
>   * type of transfer_type
> 

-- 
- Daniel

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180311/5111c25b/attachment.sig>

^ permalink raw reply	[flat|nested] 106+ messages in thread

end of thread, other threads:[~2018-03-11 19:14 UTC | newest]

Thread overview: 106+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-12 16:38 [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 01/14] dma: add dma channels support and improve uclass Álvaro Fernández Rojas
2018-02-20  8:24   ` Vignesh R
2018-02-12 16:38 ` [U-Boot] [RFC 02/14] dma: add bcm6348-iudma support Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 03/14] bmips: bcm6338: " Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 04/14] bmips: bcm6348: " Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 05/14] bmips: bcm6358: " Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 06/14] phy: add support for internal phys Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 07/14] net: add support for bcm6348-enet Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 08/14] bmips: bcm6338: " Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 09/14] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 10/14] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 11/14] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 12/14] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 13/14] bmips: enable hg556a enet support Álvaro Fernández Rojas
2018-02-12 16:38 ` [U-Boot] [RFC 14/14] bmips: enable nb4-ser " Álvaro Fernández Rojas
2018-02-19 17:26 ` [U-Boot] [RFC 00/14] bmips: add bcm6348-enet support Álvaro Fernández Rojas
2018-02-20 17:46 ` [U-Boot] [RFC v2 00/15] " Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
2018-02-20 18:49     ` Simon Glass
2018-02-20 18:55       ` Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 02/15] dma: add channels support Álvaro Fernández Rojas
2018-02-20 18:49     ` Simon Glass
2018-02-20 19:00       ` Álvaro Fernández Rojas
2018-02-21 15:51       ` Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 04/15] bmips: bcm6338: " Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 05/15] bmips: bcm6348: " Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 06/15] bmips: bcm6358: " Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 07/15] phy: add support for internal phys Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 09/15] bmips: bcm6338: " Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 10/15] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 11/15] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 12/15] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 13/15] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 14/15] bmips: enable hg556a enet support Álvaro Fernández Rojas
2018-02-20 17:46   ` [U-Boot] [RFC v2 15/15] bmips: enable nb4-ser " Álvaro Fernández Rojas
2018-02-21 16:10 ` [U-Boot] [RFC v3 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
2018-02-22 16:18     ` Simon Glass
2018-03-05 19:35       ` Grygorii Strashko
2018-03-05 20:06         ` Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 02/15] dma: add channels support Álvaro Fernández Rojas
2018-02-22 16:18     ` Simon Glass
2018-02-21 16:10   ` [U-Boot] [RFC v3 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
2018-02-22 19:50     ` Grygorii Strashko
2018-02-22 20:48       ` Álvaro Fernández Rojas
2018-02-23 16:57         ` Grygorii Strashko
2018-03-03  9:06           ` Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 04/15] bmips: bcm6338: " Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 05/15] bmips: bcm6348: " Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 06/15] bmips: bcm6358: " Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 07/15] phy: add support for internal phys Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 09/15] bmips: bcm6338: " Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 10/15] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 11/15] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 12/15] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 13/15] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 14/15] bmips: enable hg556a enet support Álvaro Fernández Rojas
2018-02-21 16:10   ` [U-Boot] [RFC v3 15/15] bmips: enable nb4-ser " Álvaro Fernández Rojas
2018-03-03  8:59 ` [U-Boot] [RFC v4 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
2018-03-05 19:38     ` Grygorii Strashko
2018-03-03  8:59   ` [U-Boot] [RFC v4 02/15] dma: add channels support Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 04/15] bmips: bcm6338: " Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 05/15] bmips: bcm6348: " Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 06/15] bmips: bcm6358: " Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 07/15] phy: add support for internal phys Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 09/15] bmips: bcm6338: " Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 10/15] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 11/15] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 12/15] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 13/15] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 14/15] bmips: enable hg556a enet support Álvaro Fernández Rojas
2018-03-03  8:59   ` [U-Boot] [RFC v4 15/15] bmips: enable nb4-ser " Álvaro Fernández Rojas
2018-03-05 20:05 ` [U-Boot] [PATCH v5 00/15] bmips: add bcm6348-enet support Álvaro Fernández Rojas
2018-03-05 20:05   ` [U-Boot] [PATCH v5 01/15] dma: move dma_ops to dma-uclass.h Álvaro Fernández Rojas
2018-03-06 15:10     ` Grygorii Strashko
2018-03-05 20:05   ` [U-Boot] [PATCH v5 02/15] dma: add channels support Álvaro Fernández Rojas
2018-03-07 21:27     ` Joe Hershberger
2018-03-08 19:46       ` Álvaro Fernández Rojas
2018-03-08 23:07     ` Grygorii Strashko
2018-03-09 18:42       ` Álvaro Fernández Rojas
2018-03-11 19:14     ` Daniel Schwierzeck
2018-03-05 20:05   ` [U-Boot] [PATCH v5 03/15] dma: add bcm6348-iudma support Álvaro Fernández Rojas
2018-03-05 20:05   ` [U-Boot] [PATCH v5 04/15] bmips: bcm6338: " Álvaro Fernández Rojas
2018-03-05 20:05   ` [U-Boot] [PATCH v5 05/15] bmips: bcm6348: " Álvaro Fernández Rojas
2018-03-05 20:05   ` [U-Boot] [PATCH v5 06/15] bmips: bcm6358: " Álvaro Fernández Rojas
2018-03-05 20:05   ` [U-Boot] [PATCH v5 07/15] phy: add support for internal phys Álvaro Fernández Rojas
2018-03-07 20:28     ` Joe Hershberger
2018-03-08 19:38       ` Álvaro Fernández Rojas
2018-03-08 20:11         ` Joe Hershberger
2018-03-05 20:05   ` [U-Boot] [PATCH v5 08/15] net: add support for bcm6348-enet Álvaro Fernández Rojas
2018-03-07 21:46     ` Joe Hershberger
2018-03-08 19:50       ` Álvaro Fernández Rojas
2018-03-05 20:05   ` [U-Boot] [PATCH v5 09/15] bmips: bcm6338: " Álvaro Fernández Rojas
2018-03-05 20:05   ` [U-Boot] [PATCH v5 10/15] bmips: enable f@st1704 enet support Álvaro Fernández Rojas
2018-03-05 20:05   ` [U-Boot] [PATCH v5 11/15] bmips: bcm6348: add support for bcm6348-enet Álvaro Fernández Rojas
2018-03-05 20:05   ` [U-Boot] [PATCH v5 12/15] bmips: enable ct-5361 enet support Álvaro Fernández Rojas
2018-03-05 20:05   ` [U-Boot] [PATCH v5 13/15] bmips: bcm6358: add support for bcm6348-enet Álvaro Fernández Rojas
2018-03-05 20:05   ` [U-Boot] [PATCH v5 14/15] bmips: enable hg556a enet support Álvaro Fernández Rojas
2018-03-05 20:05   ` [U-Boot] [PATCH v5 15/15] bmips: enable nb4-ser " Álvaro Fernández Rojas

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.