Add driver for the IHS IO endpoint on IHS FPGAs. Signed-off-by: Mario Six <mario....@gdsys.cc>
--- v2 -> v3: No changes v1 -> v2: * Switched to regmap usage (instead of fpgamap) --- drivers/misc/Kconfig | 6 ++ drivers/misc/Makefile | 1 + drivers/misc/gdsys_ioep.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/gdsys_ioep.h | 73 ++++++++++++++++++++++ 4 files changed, 235 insertions(+) create mode 100644 drivers/misc/gdsys_ioep.c create mode 100644 drivers/misc/gdsys_ioep.h diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index be900cf4d6e..dc4cd4ec110 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -268,4 +268,10 @@ config GDSYS_RXAUI_CTRL depends on MISC 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 e362609d62a..1782dc8be42 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -53,3 +53,4 @@ obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_STM32_RCC) += stm32_rcc.o obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.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 00000000000..2c29e8c4e8c --- /dev/null +++ b/drivers/misc/gdsys_ioep.c @@ -0,0 +1,155 @@ +/* + * (C) Copyright 2017 + * Mario Six, Guntermann & Drunck GmbH, mario....@gdsys.cc + * + * based on the cmd_ioloop driver/command, which is + * + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eib...@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <misc.h> +#include <regmap.h> + +#include "gdsys_ioep.h" + +struct gdsys_ioep_priv { + struct regmap *map; + bool state; +}; + +enum last_spec { + READ_DATA_IS_LAST, + READ_DATA_IS_NOT_LAST, +}; + +int gdsys_ioep_set_receive(struct udevice *dev, bool val) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + u16 state; + + priv->state = !priv->state; + + if (val) + state = CTRL_PROC_RECEIVE_ENABLE; + else + state = ~CTRL_PROC_RECEIVE_ENABLE; + + gdsys_ioep_set(priv->map, tx_control, state); + + if (val) { + /* Set device address to dummy 1*/ + gdsys_ioep_set(priv->map, device_address, 1); + } + + return !priv->state; +} + +int gdsys_ioep_send(struct udevice *dev, int offset, const void *buf, int size) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + int k; + u16 *p = (u16 *)buf; + + for (k = 0; k < size; ++k) + gdsys_ioep_set(priv->map, transmit_data, *(p++)); + + gdsys_ioep_set(priv->map, tx_control, CTRL_PROC_RECEIVE_ENABLE | + CTRL_FLUSH_TRANSMIT_BUFFER); + + return 0; +} + +int receive_byte_buffer(struct udevice *dev, uint len, u16 *buffer, enum last_spec last_spec) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + int k; + int res = -EIO; + + for (k = 0; k < len; ++k) { + u16 rx_tx_status; + + gdsys_ioep_get(priv->map, receive_data, buffer++); + + gdsys_ioep_get(priv->map, rx_tx_status, &rx_tx_status); + if (k == (len - 1) && (last_spec == READ_DATA_IS_NOT_LAST || + rx_tx_status & STATE_RX_DATA_LAST)) + res = 0; + } + + return res; +} + +int gdsys_ioep_receive(struct udevice *dev, int offset, void *buf, int size) +{ + int res1, res2; + struct io_generic_packet header; + u16 *p = (u16 *)buf; + const int header_words = sizeof(struct io_generic_packet) / 2; + uint len; + + res1 = receive_byte_buffer(dev, header_words, p, READ_DATA_IS_NOT_LAST); + memcpy(&header, p, 2 * header_words); + p += header_words; + + len = (header.packet_length + 1) / 2; + + if (!res1) + res2 = receive_byte_buffer(dev, len, p, READ_DATA_IS_LAST); + + return res1 ? res1 : res2; +} + +int gdsys_ioep_get_and_reset_status(struct udevice *dev, int msgid, + void *tx_msg, int tx_size, void *rx_msg, + int rx_size) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + const 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 = rx_msg; + + gdsys_ioep_get(priv->map, rx_tx_status, status); + + gdsys_ioep_set(priv->map, rx_tx_status, *status); + + return (*status & mask) ? 1 : 0; +} + +static const struct misc_ops gdsys_ioep_ops = { + .set_enabled = gdsys_ioep_set_receive, + .write = gdsys_ioep_send, + .read = gdsys_ioep_receive, + .call = gdsys_ioep_get_and_reset_status, +}; + +int gdsys_ioep_probe(struct udevice *dev) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + + regmap_init_mem(dev_ofnode(dev), &priv->map); + + priv->state = false; + + return 0; +} + +static const struct udevice_id gdsys_ioep_ids[] = { + { .compatible = "gdsys,io-endpoint" }, + { } +}; + +U_BOOT_DRIVER(gdsys_ioep) = { + .name = "gdsys_ioep", + .id = UCLASS_MISC, + .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/drivers/misc/gdsys_ioep.h b/drivers/misc/gdsys_ioep.h new file mode 100644 index 00000000000..cccf5800919 --- /dev/null +++ b/drivers/misc/gdsys_ioep.h @@ -0,0 +1,73 @@ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario....@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __GDSYS_IOEP_H_ +#define __GDSYS_IOEP_H_ + +/** + * 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 bytes. + */ +struct io_generic_packet { + u16 target_address; + u16 source_address; + u8 packet_type; + u8 bc; + u16 packet_length; +} __attribute__((__packed__)); + +struct gdsys_ioep_regs { + u16 transmit_data; + u16 tx_control; + u16 receive_data; + u16 rx_tx_status; + u16 device_address; + u16 target_address; + u16 int_enable; +}; + +#define gdsys_ioep_set(map, member, val) \ + regmap_set(map, struct gdsys_ioep_regs, member, val) + +#define gdsys_ioep_get(map, member, valp) \ + regmap_get(map, struct gdsys_ioep_regs, member, valp) +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), +}; + +#endif /* __GDSYS_IOEP_H_ */ -- 2.11.0 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot