[U-Boot] [PATCH 39/51] drivers: Add gdsys_ioep driver

Mario Six mario.six at gdsys.cc
Fri Jul 14 12:55:25 UTC 2017


Add driver for the IHS IO endpoint on IHS FPGAs.

Signed-off-by: Mario Six <mario.six at gdsys.cc>
---

 drivers/misc/Kconfig      |   6 +
 drivers/misc/Makefile     |   1 +
 drivers/misc/gdsys_ioep.c | 301 ++++++++++++++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h    |   1 +
 include/gdsys_ioep.h      | 196 ++++++++++++++++++++++++++++++
 5 files changed, 505 insertions(+)
 create mode 100644 drivers/misc/gdsys_ioep.c
 create mode 100644 include/gdsys_ioep.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index dd768e2a7a..f8885380d0 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -221,4 +221,10 @@ config GDSYS_RXAUI_CTRL
 	help
 	  Support gdsys FPGA's RXAUI control.
 
+config GDSYS_IOEP
+	bool "Enable gdsys IOEP driver"
+	depends on MISC
+	help
+	  Support gdsys FPGA's IO endpoint driver.
+
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 3ff9e66da2..40788c9acc 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,3 +56,4 @@ obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o gdsys_soc.o
 obj-$(CONFIG_IHS_AXI) += ihs_axi.o
 obj-$(CONFIG_IHS_VIDEO_OUT) += ihs_video_out.o
 obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
+obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o
diff --git a/drivers/misc/gdsys_ioep.c b/drivers/misc/gdsys_ioep.c
new file mode 100644
index 0000000000..5bf1796a40
--- /dev/null
+++ b/drivers/misc/gdsys_ioep.c
@@ -0,0 +1,301 @@
+/*
+ * (C) Copyright 2017
+ * Mario Six,  Guntermann & Drunck GmbH, mario.six at gdsys.cc
+ *
+ * based on the cmd_ioloop driver/command, which is
+ *
+ * (C) Copyright 2014
+ * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach at gdsys.cc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <gdsys_soc.h>
+#include <ihs_fpga.h>
+#include <gdsys_ioep.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+	REG_TRANSMIT_DATA = 0x0,
+	REG_TX_CONTROL = 0x2,
+	REG_RECEIVE_DATA = 0x4,
+	REG_RX_TX_STATUS = 0x6,
+	REG_DEVICE_ADDRESS = 0xA,
+	REG_TARGET_ADDRESS = 0xC,
+	REG_INT_ENABLE = 0xE,
+};
+
+enum {
+	STATE_TX_PACKET_BUILDING = BIT(0),
+	STATE_TX_TRANSMITTING = BIT(1),
+	STATE_TX_BUFFER_FULL = BIT(2),
+	STATE_TX_ERR = BIT(3),
+	STATE_RECEIVE_TIMEOUT = BIT(4),
+	STATE_PROC_RX_STORE_TIMEOUT = BIT(5),
+	STATE_PROC_RX_RECEIVE_TIMEOUT = BIT(6),
+	STATE_RX_DIST_ERR = BIT(7),
+	STATE_RX_LENGTH_ERR = BIT(8),
+	STATE_RX_FRAME_CTR_ERR = BIT(9),
+	STATE_RX_FCS_ERR = BIT(10),
+	STATE_RX_PACKET_DROPPED = BIT(11),
+	STATE_RX_DATA_LAST = BIT(12),
+	STATE_RX_DATA_FIRST = BIT(13),
+	STATE_RX_DATA_AVAILABLE = BIT(15),
+};
+
+enum {
+	CTRL_PROC_RECEIVE_ENABLE = BIT(12),
+	CTRL_FLUSH_TRANSMIT_BUFFER = BIT(15),
+};
+
+enum {
+	IRQ_CPU_TRANSMITBUFFER_FREE_STATUS = BIT(5),
+	IRQ_CPU_PACKET_TRANSMITTED_EVENT = BIT(6),
+	IRQ_NEW_CPU_PACKET_RECEIVED_EVENT = BIT(7),
+	IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS = BIT(8),
+};
+
+struct gdsys_ioep_priv {
+	int addr;
+};
+
+int ioep_enable_receive(struct udevice *dev)
+{
+	struct ioep_ops *ops = ioep_get_ops(dev);
+
+	return ops->enable_receive(dev);
+}
+
+int ioep_disable_receive(struct udevice *dev)
+{
+	struct ioep_ops *ops = ioep_get_ops(dev);
+
+	return ops->disable_receive(dev);
+}
+
+int ioep_send(struct udevice *dev, struct io_generic_packet *header, u16 *data)
+{
+	struct ioep_ops *ops = ioep_get_ops(dev);
+
+	return ops->send(dev, header, data);
+}
+
+int ioep_receive(struct udevice *dev, struct io_generic_packet *header,
+		 u16 *data)
+{
+	struct ioep_ops *ops = ioep_get_ops(dev);
+
+	return ops->receive(dev, header, data);
+}
+
+int ioep_set_address(struct udevice *dev, u16 addr)
+{
+	struct ioep_ops *ops = ioep_get_ops(dev);
+
+	return ops->set_address(dev, addr);
+}
+
+bool ioep_data_available(struct udevice *dev)
+{
+	struct ioep_ops *ops = ioep_get_ops(dev);
+
+	return ops->data_available(dev);
+}
+
+int ioep_reset_status(struct udevice *dev, bool print_status)
+{
+	struct ioep_ops *ops = ioep_get_ops(dev);
+
+	return ops->reset_status(dev, print_status);
+}
+
+UCLASS_DRIVER(ioep) = {
+	.id		= UCLASS_IOEP,
+	.name		= "ioep",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+};
+
+int gdsys_ioep_enable_receive(struct udevice *dev)
+{
+	struct gdsys_ioep_priv *priv = dev_get_priv(dev);
+	struct gdsys_soc_child_platdata *pplat = dev_get_parent_platdata(dev);
+
+	fpga_out_le16(pplat->fpga, priv->addr + REG_TX_CONTROL,
+		      CTRL_PROC_RECEIVE_ENABLE);
+
+	return 0;
+}
+
+int gdsys_ioep_disable_receive(struct udevice *dev)
+{
+	struct gdsys_ioep_priv *priv = dev_get_priv(dev);
+	struct gdsys_soc_child_platdata *pplat = dev_get_parent_platdata(dev);
+
+	fpga_out_le16(pplat->fpga, priv->addr + REG_TX_CONTROL,
+		      ~CTRL_PROC_RECEIVE_ENABLE);
+
+	return 0;
+}
+
+int gdsys_ioep_send(struct udevice *dev, struct io_generic_packet *header,
+		    u16 *data)
+{
+	struct gdsys_ioep_priv *priv = dev_get_priv(dev);
+	struct gdsys_soc_child_platdata *pplat = dev_get_parent_platdata(dev);
+	int k;
+	u16 *p;
+
+	p = (u16 *)header;
+
+	for (k = 0; k < sizeof(struct io_generic_packet) / 2; ++k)
+		fpga_out_le16(pplat->fpga,
+			      priv->addr + REG_TRANSMIT_DATA, *p++);
+
+	p = (u16 *)data;
+
+	for (k = 0; k < (header->packet_length + 1) / 2; ++k)
+		fpga_out_le16(pplat->fpga,
+			      priv->addr + REG_TRANSMIT_DATA, *p++);
+
+	fpga_out_le16(pplat->fpga, priv->addr + REG_TX_CONTROL,
+		      CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER);
+
+	return 0;
+}
+
+int receive_byte_buffer(struct udevice *dev, uint len, u16 *buffer)
+{
+	struct gdsys_ioep_priv *priv = dev_get_priv(dev);
+	struct gdsys_soc_child_platdata *pplat = dev_get_parent_platdata(dev);
+	int k;
+	int res = -EIO;
+
+	for (k = 0; k < len; ++k) {
+		u16 rx_tx_status;
+
+		*buffer++ = fpga_in_le16(pplat->fpga,
+				    priv->addr + REG_RECEIVE_DATA);
+
+		rx_tx_status = fpga_in_le16(pplat->fpga,
+					    priv->addr + REG_RX_TX_STATUS);
+		if (k == len && rx_tx_status & STATE_RX_DATA_LAST)
+			res = 0;
+	}
+
+	return res;
+}
+
+int gdsys_ioep_receive(struct udevice *dev, struct io_generic_packet *header,
+		       u16 *data)
+{
+	int res1, res2;
+	u16 *p = (u16 *)header;
+
+	res1 = receive_byte_buffer(dev,
+				   sizeof(struct io_generic_packet) / 2, p);
+
+	if (!res1)
+		res2 = receive_byte_buffer(dev, header->packet_length + 1,
+					   data);
+
+	return res1 ? res1 : res2;
+}
+
+int gdsys_ioep_set_address(struct udevice *dev, u16 addr)
+{
+	struct gdsys_ioep_priv *priv = dev_get_priv(dev);
+	struct gdsys_soc_child_platdata *pplat = dev_get_parent_platdata(dev);
+
+	/* Set device address */
+	fpga_out_le16(pplat->fpga, priv->addr + REG_DEVICE_ADDRESS, addr);
+
+	return 0;
+}
+
+bool gdsys_ioep_data_available(struct udevice *dev)
+{
+	struct gdsys_ioep_priv *priv = dev_get_priv(dev);
+	struct gdsys_soc_child_platdata *pplat = dev_get_parent_platdata(dev);
+	u16 rx_tx_status;
+
+	rx_tx_status = fpga_in_le16(pplat->fpga, priv->addr + REG_RX_TX_STATUS);
+
+	return rx_tx_status & STATE_RX_DATA_AVAILABLE;
+}
+
+int gdsys_ioep_reset_status(struct udevice *dev, bool print_status)
+{
+	struct gdsys_ioep_priv *priv = dev_get_priv(dev);
+	struct gdsys_soc_child_platdata *pplat = dev_get_parent_platdata(dev);
+	u16 mask = STATE_RX_DIST_ERR | STATE_RX_LENGTH_ERR |
+		   STATE_RX_FRAME_CTR_ERR | STATE_RX_FCS_ERR |
+		   STATE_RX_PACKET_DROPPED | STATE_TX_ERR;
+
+	u16 status = fpga_in_le16(pplat->fpga, priv->addr + REG_RX_TX_STATUS);
+
+	if (!(status & mask)) {
+		fpga_out_le16(pplat->fpga, priv->addr + REG_RX_TX_STATUS,
+			      status);
+		return 0;
+	}
+
+	fpga_out_le16(pplat->fpga, priv->addr + REG_RX_TX_STATUS, status);
+
+	if (!print_status)
+		return 1;
+
+	if (status & STATE_RX_PACKET_DROPPED)
+		printf("RX_PACKET_DROPPED, status %04x\n", status);
+
+	if (status & STATE_RX_DIST_ERR)
+		printf("RX_DIST_ERR\n");
+	if (status & STATE_RX_LENGTH_ERR)
+		printf("RX_LENGTH_ERR\n");
+	if (status & STATE_RX_FRAME_CTR_ERR)
+		printf("RX_FRAME_CTR_ERR\n");
+	if (status & STATE_RX_FCS_ERR)
+		printf("RX_FCS_ERR\n");
+
+	if (status & STATE_TX_ERR)
+		printf("TX_ERR\n");
+
+	return 1;
+}
+
+static const struct ioep_ops gdsys_ioep_ops = {
+	.enable_receive = gdsys_ioep_enable_receive,
+	.disable_receive = gdsys_ioep_disable_receive,
+	.send = gdsys_ioep_send,
+	.receive = gdsys_ioep_receive,
+	.set_address = gdsys_ioep_set_address,
+	.data_available = gdsys_ioep_data_available,
+	.reset_status = gdsys_ioep_reset_status,
+};
+
+int gdsys_ioep_probe(struct udevice *dev)
+{
+	struct gdsys_ioep_priv *priv = dev_get_priv(dev);
+
+	priv->addr = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+				    "reg", -1);
+
+	return 0;
+}
+
+static const struct udevice_id gdsys_ioep_ids[] = {
+	{ .compatible = "gdsys,io-endpoint" },
+	{ }
+};
+
+U_BOOT_DRIVER(gdsys_ioep) = {
+	.name           = "gdsys_ioep",
+	.id             = UCLASS_IOEP,
+	.ops		= &gdsys_ioep_ops,
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.of_match       = gdsys_ioep_ids,
+	.probe          = gdsys_ioep_probe,
+	.priv_auto_alloc_size = sizeof(struct gdsys_ioep_priv),
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 35e478cc74..7bf8857799 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -45,6 +45,7 @@ enum uclass_id {
 	UCLASS_IHS_AXI,		/* gdsys IHS AXI bus */
 	UCLASS_IHS_FPGA,	/* gdsys IHS FPGAs */
 	UCLASS_IHS_VIDEO_OUT,	/* gdsys IHS video output */
+	UCLASS_IOEP,		/* gdsys IHS IO endpoint */
 	UCLASS_IRQ,		/* Interrupt controller */
 	UCLASS_KEYBOARD,	/* Keyboard input device */
 	UCLASS_LED,		/* Light-emitting diode (LED) */
diff --git a/include/gdsys_ioep.h b/include/gdsys_ioep.h
new file mode 100644
index 0000000000..6edf44d528
--- /dev/null
+++ b/include/gdsys_ioep.h
@@ -0,0 +1,196 @@
+/*
+ * (C) Copyright 2017
+ * Mario Six,  Guntermann & Drunck GmbH, mario.six at gdsys.cc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _GDSYS_IOEP_CTRL_H_
+#define _GDSYS_IOEP_CTRL_H_
+
+/**
+ * The GDSYS IO endpoint is a IHS FPGA interface used by gdsys devices to send
+ * and receive special data packets via a proprietary protocol.
+ */
+
+/**
+ * struct io_generic_packet - header structure for GDSYS IOEP packets
+ *
+ * @target_address:	Target protocol address of the packet.
+ * @source_address:	Source protocol address of the packet.
+ * @packet_type:	Packet type.
+ * @bc:			Block counter (filled in by FPGA).
+ * @packet_length:	Length of the packet's payload in 16 bit words.
+ */
+struct io_generic_packet {
+	u16 target_address;
+	u16 source_address;
+	u8 packet_type;
+	u8 bc;
+	u16 packet_length;
+} __attribute__((__packed__));
+
+/**
+ * struct ioep_ops - driver operations for GDSYS IOEP uclass
+ *
+ * Drivers should support these operations unless otherwise noted. These
+ * operations are intended to be used by uclass code, not directly from
+ * other code.
+ */
+struct ioep_ops {
+	/**
+	 * enable_receive() - Enable the receive path of a given GDSYS IOEP
+	 * 		      instance
+	 *
+	 * @dev:	GDSYS IOEP instance to use.
+	 * @return 0 if OK, -ve on error.
+	 */
+	int (*enable_receive)(struct udevice *dev);
+
+	/**
+	 * disable_receive() - Disable the receive path of a given GDSYS IOEP
+	 * 		       instance
+	 *
+	 * @dev:	GDSYS IOEP instance to use.
+	 * @return 0 if OK, -ve on error.
+	 */
+	int (*disable_receive)(struct udevice *dev);
+
+	/**
+	 * send() - Send a data packet through the GDSYS IOEP instance
+	 *
+	 * @dev:	GDSYS IOEP instance to use.
+	 * @header:	Header data for the packet to send (have to be filled
+	 * 		before calling this method).
+	 * @data:	Payload data for the packet as an array of 16 bit
+	 * 		values.
+	 * @return 0 if OK, -ve on error.
+	 */
+	int (*send)(struct udevice *dev, struct io_generic_packet *header,
+		    u16 *data);
+
+	/**
+	 * receive() - Receive a data packet through the GDSYS IOEP instance
+	 *
+	 * @dev:	GDSYS IOEP instance to use.
+	 * @header:	A pointer to a header data structure, which is filled
+	 * 		with the data from the received packet.
+	 * @data:	A pointer to a 16 bit array, which receives the payload
+	 * 		data from the received packet (must be large enough for
+	 * 		the data).
+	 * @return 0 if OK, -ve on error.
+	 */
+	int (*receive)(struct udevice *dev, struct io_generic_packet *header,
+		       u16 *data);
+
+	/**
+	 * set_address() - Set the protocol address for this GDSYS IOEP
+	 * 		   instance
+	 *
+	 * @dev:	GDSYS IOEP instance to use.
+	 * @addr:	The address to set (a 16 bit value)
+	 * @return 0 if OK, -ve on error.
+	 */
+	int (*set_address)(struct udevice *dev, u16 addr);
+
+	/**
+	 * data_available() - Check if a packet can be read from thie GDSYS
+	 * 		      IOEP instance.
+	 *
+	 * The packet can be read via the receive() method.
+	 *
+	 * @dev:	GDSYS IOEP instance to use.
+	 * @return true is a package can be read, false if not.
+	 */
+	bool (*data_available)(struct udevice *dev);
+
+	/**
+	 * reset_status() - Reset the error status of a GDSYS IOEP instance
+	 *
+	 * The error status *prior* to the status reset may optionally be
+	 * printed.
+	 *
+	 * @dev:		GDSYS IOEP instance to use.
+	 * @print_status:	Flag that, if set, makes the function print the
+	 * 			error status prior to resetting.
+	 * @return 0 if the instance was signalling an error prior to reset, 1
+	 *  if no error was signaled.
+	 */
+	int (*reset_status)(struct udevice *dev, bool print_status);
+};
+
+#define ioep_get_ops(dev)	((struct ioep_ops *)(dev)->driver->ops)
+
+/**
+ * ioep_enable_receive() - Enable the receive path of a given GDSYS IOEP
+ * 			   instance
+ *
+ * @dev:	GDSYS IOEP instance to use.
+ * @return 0 if OK, -ve on error.
+ */
+int ioep_enable_receive(struct udevice *dev);
+
+/**
+ * ioep_disable_receive() - Disable the receive path of a given GDSYS IOEP
+ * 			    instance
+ *
+ * @dev:	GDSYS IOEP instance to use.
+ * @return 0 if OK, -ve on error.
+ */
+int ioep_disable_receive(struct udevice *dev);
+
+/**
+ * ioep_send() - Send a data packet through the GDSYS IOEP instance
+ *
+ * @dev:	GDSYS IOEP instance to use.
+ * @header:	Header data for the packet to send (have to be filled before
+ * 		calling this method).
+ * @data:	Payload data for the packet as an array of 16 bit values.
+ * @return 0 if OK, -ve on error.
+ */
+int ioep_send(struct udevice *dev, struct io_generic_packet *header,
+	      u16 *data);
+
+/**
+ * ioep_receive() - Receive a data packet through the GDSYS IOEP instance
+ *
+ * @dev:	GDSYS IOEP instance to use.
+ * @header:	A pointer to a header data structure, which is filled with the
+ * 		data from the received packet.
+ * @data:	A pointer to a 16 bit array, which receives the payload data
+ * 		from the received packet (must be large enough for the data).
+ * @return 0 if OK, -ve on error.
+ */
+int ioep_receive(struct udevice *dev, struct io_generic_packet *header,
+		 u16 *data);
+
+/**
+ * ioep_set_address() - Set the protocol address for this GDSYS IOEP instance
+ *
+ * @dev:	GDSYS IOEP instance to use.
+ * @addr:	The address to set (a 16 bit value)
+ * @return 0 if OK, -ve on error.
+ */
+int ioep_set_address(struct udevice *dev, u16 addr);
+
+/**
+ * ioep_data_available() - Check if a packet can be read from thie GDSYS IOEP
+ * 			   instance.
+ *
+ * @dev:	GDSYS IOEP instance to use.
+ * @return true is a package can be read, false if not.
+ */
+bool ioep_data_available(struct udevice *dev);
+
+/**
+ * ioep_reset_status() - Reset the error status of a GDSYS IOEP instance
+ *
+ * @dev:		GDSYS IOEP instance to use.
+ * @print_status:	Flag that, if set, makes the function print the
+ * 			error status prior to resetting.
+ * @return 0 if the instance was signalling an error prior to reset, 1
+ *  if no error was signaled.
+ */
+int ioep_reset_status(struct udevice *dev, bool print_status);
+
+#endif /* _GDSYS_IOEP_CTRL_H_ */
-- 
2.11.0



More information about the U-Boot mailing list