From patchwork Tue Jun 18 15:47:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robert Hancock X-Patchwork-Id: 1118407 X-Patchwork-Delegate: monstr@monstr.eu 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=sedsystems.ca Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 45T7514tdwz9sN6 for ; Wed, 19 Jun 2019 11:43:17 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 32C0CC22058; Wed, 19 Jun 2019 01:41:43 +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=none 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 10589C2204E; Wed, 19 Jun 2019 01:40:51 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id D97A0C21F3C; Tue, 18 Jun 2019 15:47:34 +0000 (UTC) Received: from sed198n136.sedsystems.ca (sed198n136.SEDSystems.ca [198.169.180.136]) by lists.denx.de (Postfix) with ESMTPS id 3AADDC21F38 for ; Tue, 18 Jun 2019 15:47:34 +0000 (UTC) Received: from barney.sedsystems.ca (barney [198.169.180.121]) by sed198n136.sedsystems.ca with ESMTP id x5IFlW38025711 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 18 Jun 2019 09:47:33 -0600 (CST) Received: from SED.RFC1918.192.168.sedsystems.ca (eng1n65.eng.sedsystems.ca [172.21.1.65]) by barney.sedsystems.ca (8.14.7/8.14.4) with ESMTP id x5IFlSkg013046 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Tue, 18 Jun 2019 09:47:31 -0600 From: Robert Hancock To: u-boot@lists.denx.de Date: Tue, 18 Jun 2019 09:47:16 -0600 Message-Id: <1560872836-21456-6-git-send-email-hancock@sedsystems.ca> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1560872836-21456-1-git-send-email-hancock@sedsystems.ca> References: <1560872836-21456-1-git-send-email-hancock@sedsystems.ca> X-Scanned-By: MIMEDefang 2.64 on 198.169.180.136 X-Mailman-Approved-At: Wed, 19 Jun 2019 01:40:48 +0000 Cc: michal.simek@xilinx.com Subject: [U-Boot] [PATCH 5/5] fpga: virtex2: Add slave serial programming support 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" This adds support for slave serial programming, in addition to the previously supported slave SelectMAP mode. There are two ways that this can be used: -Using the clk and wdata callbacks in order to write image data one bit at a time using pure bit-banging. This works, but is rather painfully slow with typical image sizes. -By specifying the wbulkdata callback instead, the image loading process can be offloaded to SPI hardware. In this mode the clk and wdata callbacks do not need to be specified. This allows the image to be loaded much faster, taking only a few seconds with even relatively large images. Slave serial programming has been tested on the Kintex-7 series of FPGAs. Signed-off-by: Robert Hancock --- drivers/fpga/virtex2.c | 96 +++++++++++++++++++++++++++++++++++++++++++------- include/virtex2.h | 13 ++----- 2 files changed, 86 insertions(+), 23 deletions(-) diff --git a/drivers/fpga/virtex2.c b/drivers/fpga/virtex2.c index 5028244..3957368 100644 --- a/drivers/fpga/virtex2.c +++ b/drivers/fpga/virtex2.c @@ -3,6 +3,8 @@ * (C) Copyright 2002 * Rich Ireland, Enterasys Networks, rireland@enterasys.com. * Keith Outwater, keith_outwater@mvis.com + * + * Copyright (c) 2019 SED Systems, a division of Calian Ltd. */ /* @@ -141,8 +143,8 @@ static int virtex2_info(xilinx_desc *desc) } /* - * Virtex-II Slave SelectMap configuration loader. Configuration via - * SelectMap is as follows: + * Virtex-II Slave SelectMap or Serial configuration loader. Configuration + * is as follows: * 1. Set the FPGA's PROG_B line low. * 2. Set the FPGA's PROG_B line high. Wait for INIT_B to go high. * 3. Write data to the SelectMap port. If INIT_B goes low at any time @@ -154,7 +156,7 @@ static int virtex2_info(xilinx_desc *desc) * INIT_B and DONE lines. If both are high, configuration has * succeeded. Congratulations! */ -static int virtex2_slave_pre(xilinx_virtex2_slave_selectmap_fns *fn, int cookie) +static int virtex2_slave_pre(xilinx_virtex2_slave_fns *fn, int cookie) { unsigned long ts; @@ -243,7 +245,7 @@ static int virtex2_slave_pre(xilinx_virtex2_slave_selectmap_fns *fn, int cookie) return FPGA_SUCCESS; } -static int virtex2_slave_post(xilinx_virtex2_slave_selectmap_fns *fn, +static int virtex2_slave_post(xilinx_virtex2_slave_fns *fn, int cookie) { int ret_val = FPGA_SUCCESS; @@ -284,11 +286,16 @@ static int virtex2_slave_post(xilinx_virtex2_slave_selectmap_fns *fn, ret_val = FPGA_FAIL; break; } - (*fn->wdata) (0xff, true, cookie); - CONFIG_FPGA_DELAY(); - (*fn->clk) (false, true, cookie); - CONFIG_FPGA_DELAY(); - (*fn->clk) (true, true, cookie); + if (fn->wbulkdata) { + unsigned char dummy = 0xff; + (*fn->wbulkdata)(&dummy, 1, true, cookie); + } else { + (*fn->wdata)(0xff, true, cookie); + CONFIG_FPGA_DELAY(); + (*fn->clk)(false, true, cookie); + CONFIG_FPGA_DELAY(); + (*fn->clk)(true, true, cookie); + } } if (ret_val == FPGA_SUCCESS) { @@ -312,7 +319,7 @@ static int virtex2_slave_post(xilinx_virtex2_slave_selectmap_fns *fn, static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize) { int ret_val = FPGA_FAIL; - xilinx_virtex2_slave_selectmap_fns *fn = desc->iface_fns; + xilinx_virtex2_slave_fns *fn = desc->iface_fns; size_t bytecount = 0; unsigned char *data = (unsigned char *)buf; int cookie = desc->cookie; @@ -387,7 +394,7 @@ static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize) static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize) { int ret_val = FPGA_FAIL; - xilinx_virtex2_slave_selectmap_fns *fn = desc->iface_fns; + xilinx_virtex2_slave_fns *fn = desc->iface_fns; if (fn) { unsigned char *data = (unsigned char *)buf; @@ -438,8 +445,71 @@ static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize) static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize) { - printf("%s: Slave Serial Loading is unsupported\n", __func__); - return FPGA_FAIL; + int ret_val = FPGA_FAIL; + xilinx_virtex2_slave_fns *fn = desc->iface_fns; + unsigned char *data = (unsigned char *)buf; + int cookie = desc->cookie; + + ret_val = virtex2_slave_pre(fn, cookie); + if (ret_val != FPGA_SUCCESS) + return ret_val; + + if (fn->wbulkdata) { + /* Load the data in a single chunk */ + (*fn->wbulkdata)(data, bsize, true, cookie); + } else { + size_t bytecount = 0; + + /* + * Load the data bit by bit + */ + while (bytecount < bsize) { + unsigned char curr_data = data[bytecount++]; + int bit; + +#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC + if (ctrlc()) { + (*fn->abort) (cookie); + return FPGA_FAIL; + } +#endif + + if ((*fn->done)(cookie) == FPGA_SUCCESS) { + PRINTF("%s:%d:done went active early, bytecount = %d\n", + __func__, __LINE__, bytecount); + break; + } + +#ifdef CONFIG_SYS_FPGA_CHECK_ERROR + if ((*fn->init)(cookie)) { + printf("\n%s:%d: ** Error: INIT asserted during configuration\n", + __func__, __LINE__); + printf("%zu = buffer offset, %zu = buffer size\n", + bytecount, bsize); + (*fn->abort)(cookie); + return FPGA_FAIL; + } +#endif + + for (bit = 7; bit >= 0; --bit) { + unsigned char curr_bit = (curr_data >> bit) & 1; + (*fn->wdata)(curr_bit, true, cookie); + CONFIG_FPGA_DELAY(); + (*fn->clk)(false, true, cookie); + CONFIG_FPGA_DELAY(); + (*fn->clk)(true, true, cookie); + } + + /* Slave serial never uses a busy pin */ + +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK + if (bytecount % (bsize / 40) == 0) + putc('.'); +#endif + } + } + + return virtex2_slave_post(fn, cookie); } static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize) diff --git a/include/virtex2.h b/include/virtex2.h index a481130..7e8d93f 100644 --- a/include/virtex2.h +++ b/include/virtex2.h @@ -11,7 +11,7 @@ #include /* - * Slave SelectMap Implementation function table. + * Slave SelectMap or Serial Implementation function table. */ typedef struct { xilinx_pre_fn pre; @@ -24,18 +24,11 @@ typedef struct { xilinx_wr_fn wr; xilinx_rdata_fn rdata; xilinx_wdata_fn wdata; + xilinx_bwr_fn wbulkdata; xilinx_busy_fn busy; xilinx_abort_fn abort; xilinx_post_fn post; -} xilinx_virtex2_slave_selectmap_fns; - -/* Slave Serial Implementation function table */ -typedef struct { - xilinx_pgm_fn pgm; - xilinx_clk_fn clk; - xilinx_rdata_fn rdata; - xilinx_wdata_fn wdata; -} xilinx_virtex2_slave_serial_fns; +} xilinx_virtex2_slave_fns; #if defined(CONFIG_FPGA_VIRTEX2) extern struct xilinx_fpga_op virtex2_op;