From patchwork Wed Mar 28 12:38:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Six X-Patchwork-Id: 892158 X-Patchwork-Delegate: mario.six@gdsys.cc Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gdsys.cc Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 40B71K56Wlz9ryk for ; Wed, 28 Mar 2018 23:46:45 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id 2F7EAC220A8; Wed, 28 Mar 2018 12:43:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id C4BA0C220FD; Wed, 28 Mar 2018 12:39:38 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id CB60CC220F7; Wed, 28 Mar 2018 12:38:22 +0000 (UTC) Received: from smtprelay02.ispgateway.de (smtprelay02.ispgateway.de [80.67.31.25]) by lists.denx.de (Postfix) with ESMTPS id 993CAC22070 for ; Wed, 28 Mar 2018 12:38:18 +0000 (UTC) Received: from [87.191.40.34] (helo=bob3.testumgebung.local) by smtprelay02.ispgateway.de with esmtpa (Exim 4.90_1) (envelope-from ) id 1f1ALa-0007ol-DC; Wed, 28 Mar 2018 14:38:34 +0200 From: Mario Six To: U-Boot Mailing List , Simon Glass Date: Wed, 28 Mar 2018 14:38:09 +0200 Message-Id: <20180328123809.16210-2-mario.six@gdsys.cc> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180328123809.16210-1-mario.six@gdsys.cc> References: <20180328123809.16210-1-mario.six@gdsys.cc> X-Df-Sender: bWFyaW8uc2l4QGdkc3lzLmNj Subject: [U-Boot] [PATCH 2/2] misc: Add gdsys_ioep driver X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Add driver for the IHS IO endpoint on IHS FPGAs. Signed-off-by: Mario Six --- drivers/misc/Kconfig | 6 +- drivers/misc/Makefile | 1 + drivers/misc/gdsys_ioep.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/gdsys_ioep.h | 68 +++++++++++++++++ 4 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 drivers/misc/gdsys_ioep.c create mode 100644 drivers/misc/gdsys_ioep.h -- 2.16.1 diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index d774569cbc..bdcf9aac5b 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -263,5 +263,9 @@ config SYS_I2C_EEPROM_ADDR_OVERFLOW endif - +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 e8d598cd47..0aa1e3fa4b 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -54,3 +54,4 @@ obj-$(CONFIG_QFW) += qfw.o 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_IOEP) += gdsys_ioep.o diff --git a/drivers/misc/gdsys_ioep.c b/drivers/misc/gdsys_ioep.c new file mode 100644 index 0000000000..3b31e26d5c --- /dev/null +++ b/drivers/misc/gdsys_ioep.c @@ -0,0 +1,183 @@ +/* + * (C) Copyright 2017 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * based on the cmd_ioloop driver/command, which is + * + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#include "gdsys_ioep.h" +#include "../misc/gdsys_soc.h" + +struct gdsys_ioep_priv { + int addr; +}; + +enum last_spec { + READ_DATA_IS_LAST, + READ_DATA_IS_NOT_LAST, +}; + +int gdsys_ioep_enable_receive(struct udevice *dev) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + struct udevice *fpga; + u16 val; + + gdsys_soc_get_fpga(dev, &fpga); + + val = CTRL_PROC_RECEIVE_ENABLE; + fpgamap_write(fpga, priv->addr + REG_TX_CONTROL, &val, + FPGAMAP_SIZE_16); + + /* Set device address to dummy 1*/ + val = 1; + fpgamap_write(fpga, priv->addr + REG_DEVICE_ADDRESS, &val, + FPGAMAP_SIZE_16); + + return 0; +} + +int gdsys_ioep_disable_receive(struct udevice *dev) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + struct udevice *fpga; + u16 val; + + gdsys_soc_get_fpga(dev, &fpga); + + val = ~CTRL_PROC_RECEIVE_ENABLE; + fpgamap_write(fpga, priv->addr + REG_TX_CONTROL, &val, + FPGAMAP_SIZE_16); + + return 0; +} + +int gdsys_ioep_send(struct udevice *dev, int offset, const void *buf, int size) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + struct udevice *fpga; + int k; + u16 *p = (u16 *)buf; + u16 val; + + gdsys_soc_get_fpga(dev, &fpga); + + for (k = 0; k < size; ++k) + fpgamap_write(fpga, priv->addr + REG_TRANSMIT_DATA, p++, + FPGAMAP_SIZE_16); + + val = CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER; + fpgamap_write(fpga, priv->addr + REG_TX_CONTROL, &val, + FPGAMAP_SIZE_16); + + 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); + struct udevice *fpga; + int k; + int res = -EIO; + + gdsys_soc_get_fpga(dev, &fpga); + + for (k = 0; k < len; ++k) { + u16 rx_tx_status; + + fpgamap_read(fpga, priv->addr + REG_RECEIVE_DATA, buffer++, + FPGAMAP_SIZE_16); + + fpgamap_read(fpga, priv->addr + REG_RX_TX_STATUS, + &rx_tx_status, FPGAMAP_SIZE_16); + 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); + struct udevice *fpga; + 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_soc_get_fpga(dev, &fpga); + + fpgamap_read(fpga, priv->addr + REG_RX_TX_STATUS, status, + FPGAMAP_SIZE_16); + + fpgamap_write(fpga, priv->addr + REG_RX_TX_STATUS, status, + FPGAMAP_SIZE_16); + + return (*status & mask) ? 1 : 0; +} + +static const struct misc_ops gdsys_ioep_ops = { + .enable = gdsys_ioep_enable_receive, + .disable = gdsys_ioep_disable_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); + + priv->addr = dev_read_u32_default(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_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 0000000000..5409bbad54 --- /dev/null +++ b/drivers/misc/gdsys_ioep.h @@ -0,0 +1,68 @@ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@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__)); + +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), +}; + +#endif /* __GDSYS_IOEP_H_ */