Received: by 2002:a05:6a10:1287:0:0:0:0 with SMTP id d7csp4036345pxv; Mon, 19 Jul 2021 15:05:30 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxpm8my0FCQperfpgmoKa1fFmbe09oNjl/7JaWLBLwIusQuK1fmITRLfSCQl1x5mSShVTUf X-Received: by 2002:a17:906:fb12:: with SMTP id lz18mr29847283ejb.324.1626732329896; Mon, 19 Jul 2021 15:05:29 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1626732329; cv=pass; d=google.com; s=arc-20160816; b=bhsnVYwVP8au43kZaQZGxfvD6M7ozAvFj8ZsZGeU+67H16bMwV7iiYFkP4ZkPoZGOd Ij3Iw99Y0CJjUmqrepVnVFOFgr7VyO6XGn+ov0dshKPmnVvHpwzuYXcNonmzRThGXlsg K9T+Gt5oiMXS87GqzVdnzR1d2Zn3JHa02KYQ3WT+uc6ns/IUXPFRZej4Q/5aGazfNUsM chaLNFO0nJgfPJR561GICdcQdlD61Mq0xYN/elwlZ+a5s/+W1NJbL2IKB0g6ibFnvZnh 3UjTfsKYC+yZnjlEDbE3SzzXZTM/z9aCMWi6iPDFnxxAWBwwuGSVjVBP2ZzwymDTTJu5 ikrw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :envelope-to:dkim-signature; bh=H73oNWFUlPijWaqmttCUfHvL9wgxRm1nQnYKC4IQPPo=; b=Jj19v8GC6lAcTNiBiukr8xXPBUW0tQadLdOwoNz9CLJjT7LUrQ7C17iwTERxX3JZhB Zb24Ko0mK3pOXKb9cmp3XrtyTPe22ItBtBYe6m4huDgEQkbtCb29GKQ6Z0XEmxaKUp0e itraR5JflD3Ygsshsz3IRt6O9M8vhO/JWbDLmPf3E9tHerxtgOMWbzX5ldr/cgrQX/3I wjv5B8iHCEXPchQ82ETISdVwlccDtNdSfPSW0U1ivFbkdGfOtI1I9/AymwkIj7DtBG1f 1bVvEXVI+t+ZOSS+orxfi6BNVVdXkgN0fpmqr0hmAf7nMXLF+j2S2arwx5XXhGHHuwMU trjg== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@xilinx.onmicrosoft.com header.s=selector2-xilinx-onmicrosoft-com header.b="q/IjwjlB"; arc=pass (i=1 spf=pass spfdomain=xilinx.com dmarc=pass fromdomain=xilinx.com); spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=xilinx.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id eb13si16684175edb.290.2021.07.19.15.05.04; Mon, 19 Jul 2021 15:05:29 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@xilinx.onmicrosoft.com header.s=selector2-xilinx-onmicrosoft-com header.b="q/IjwjlB"; arc=pass (i=1 spf=pass spfdomain=xilinx.com dmarc=pass fromdomain=xilinx.com); spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=xilinx.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1389246AbhGSVSn (ORCPT + 99 others); Mon, 19 Jul 2021 17:18:43 -0400 Received: from mail-dm6nam11on2055.outbound.protection.outlook.com ([40.107.223.55]:27873 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1388270AbhGSUsY (ORCPT ); Mon, 19 Jul 2021 16:48:24 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=O98mg6c8JPqKT4H04N74ihPLWglZNxrLjMGXC8QuPvu1dDJqGVBtASBv9oo2AoO/5tDUNaAvg0U/e6zlizAgb92t60KTDk6QA25Tz1qNfIlit31u7WXjmJJwj7B4+MkA6B8OyYa0wBR13sGOyIHaGQDbPw3dGIkP+mRMiwhhYpCNJhl67T5SXIWOnfqYx0E5SYhhRkEW0KsfY1urEOYYoWrSpPxdPwVPrBJc43Z0GL/RoI0jPU9qz7e5V4KcbS3cSgjdA4jqaH5FfTl/E001YpTtZ035/3hLr+Dvmuit1eSz55n9uVD7LQzyH4HGSHbZcq1dTfrHtcChQGYjIMesaQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=H73oNWFUlPijWaqmttCUfHvL9wgxRm1nQnYKC4IQPPo=; b=acnYbYlZI79iLqMjITUIyhiTkXhsIad8I7vRHdf6EcNbLUkyoYYNghnzfsXTKrv0U3rv/tH0+aVxjxwCFnZCh2075wXjtblhJ6J12c1gMYSJ68JCeG8bHrmBXt02ZV7CC9JN65sbo2CSB4VCQb7mqX4FR3WyZNsuNgEowSoFLi3Praxs8llsJYryINB/JpwCsaP5LHGRh6h1CRLIjwLuqGw+QJrIX+zqr12f0C11b0GkW7HrdtgyOD6wsI3yKBwgqx2lpDyPZ+5UnU5/vuSVknTPvL7NIo5xfuP+emKCkSnM63Ow3EtWJPZKi29BHk3xkXuvCv4gcUTKr13i0Yaisw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 149.199.62.198) smtp.rcpttodomain=kernel.org smtp.mailfrom=xilinx.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=xilinx.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xilinx.onmicrosoft.com; s=selector2-xilinx-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=H73oNWFUlPijWaqmttCUfHvL9wgxRm1nQnYKC4IQPPo=; b=q/IjwjlBnTKdgcOx5IyPD/TXLQ5hF1h/nU3TM5kewaM318g22dSIFjJoalP/uKLJhn1BHPRIqkgqd/VLDWfIdBN9qOrXsY4GpK2u+iLTwrfkl6AhAXSu75Ce3oaCnQhY2G1U+OiO9b54YOWJFSiMZWLwSufmBync3PvkJSr2/ag= Received: from DM6PR08CA0026.namprd08.prod.outlook.com (2603:10b6:5:80::39) by PH0PR02MB7589.namprd02.prod.outlook.com (2603:10b6:510:5a::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4331.21; Mon, 19 Jul 2021 21:28:57 +0000 Received: from DM3NAM02FT021.eop-nam02.prod.protection.outlook.com (2603:10b6:5:80:cafe::59) by DM6PR08CA0026.outlook.office365.com (2603:10b6:5:80::39) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4331.31 via Frontend Transport; Mon, 19 Jul 2021 21:28:57 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 149.199.62.198) smtp.mailfrom=xilinx.com; kernel.org; dkim=none (message not signed) header.d=none;kernel.org; dmarc=pass action=none header.from=xilinx.com; Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.62.198 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.62.198; helo=xsj-pvapexch01.xlnx.xilinx.com; Received: from xsj-pvapexch01.xlnx.xilinx.com (149.199.62.198) by DM3NAM02FT021.mail.protection.outlook.com (10.13.4.249) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4331.21 via Frontend Transport; Mon, 19 Jul 2021 21:28:57 +0000 Received: from xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) by xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.2; Mon, 19 Jul 2021 14:28:56 -0700 Received: from smtp.xilinx.com (172.19.127.95) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server id 15.1.2176.2 via Frontend Transport; Mon, 19 Jul 2021 14:28:56 -0700 Envelope-to: mdf@kernel.org, robh@kernel.org, trix@redhat.com, devicetree@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Received: from [172.19.73.109] (port=38294 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1m5aoq-00050I-Eb; Mon, 19 Jul 2021 14:28:56 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 57EE26020C5; Mon, 19 Jul 2021 14:26:32 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V8 XRT Alveo 12/14] fpga: xrt: ICAP driver Date: Mon, 19 Jul 2021 14:26:26 -0700 Message-ID: <20210719212628.134129-13-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210719212628.134129-1-lizhi.hou@xilinx.com> References: <20210719212628.134129-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 43fc4e4d-924f-4a10-4501-08d94afc37c4 X-MS-TrafficTypeDiagnostic: PH0PR02MB7589: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:6430; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: m8zaEMKAK3gNfkL98DGFv9n/YYDKxSjaJRR+w4MPv2lUSk0osN/FoBJjMaFBYmwgEa4NwuuPperLBdXkmeEynMSCAVZox1+6mtbWpuvt+t2JyspA4n9pfuopnaM8cxf80e9P9pv0IowQ40DvZHedNSFy89Ebr//mazmgNL3eDBaI0i94pezN8VveIlC5Amq2iBjnVPLJVnnbmsLrUsb9c0t4nyIhUMuAobpxJHlx37YH7qH/B8la0r0AoR3HZQK8U7tJ6iCeHPhSJBns/KdA+aKL3iYu+JiWLaYsgdfWStX8nYsLLH9ee2NzqRSrhICNhvUYwH2AhP/X5heW9zWPSUlghkGNx7WfJ+egOPH7u8lmVb33L/hkKHWWTZTNLKSmHuUYJp0Tp3VE7oGo09FM8lqKi+8uJNvOPDgcIb2s26PHp8RVfTk1/w+9x8a6wKHQpGc7UtINgdL7KTWPMkg6MT0RYAJwXyXELPhl653kUwBmBgr0tHN0r4K1fyx+kW3okPZRpVXP4kgH+UTrpS4rCiELDbTeh2vANgxoAO4v+BTCw+1nxhObnYIevrYLzAxGbCEYNNYVmGXArq8SLy115smg5jYXVzQzryx1alxXuv0YSr9M7yzIypRpEy2LjsdnHBh/K8a/lIHK1wBZJWHtWDN6aH/VraDEeJ/GujcuZ+JP4ugBhtTkbLi7NFst11GSMQO7Q9wqFp90Fd3nvfHdiDLBxqSVws0dw68Ls5VKGN3PnlypsKw2VM1TZ048nLeEnEG1dJJCmrzdOYgJpamhkcEF5R2b+AF3xhoYHQDV9Y4= X-Forefront-Antispam-Report: CIP:149.199.62.198;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:xsj-pvapexch01.xlnx.xilinx.com;PTR:unknown-62-198.xilinx.com;CAT:NONE;SFS:(4636009)(36840700001)(46966006)(54906003)(8676002)(44832011)(966005)(8936002)(70586007)(70206006)(2906002)(336012)(36756003)(42186006)(316002)(36906005)(426003)(4326008)(7636003)(2616005)(508600001)(186003)(5660300002)(6266002)(82310400003)(107886003)(1076003)(26005)(36860700001)(356005)(83380400001)(6916009)(6666004)(47076005);DIR:OUT;SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 19 Jul 2021 21:28:57.6549 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 43fc4e4d-924f-4a10-4501-08d94afc37c4 X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c;Ip=[149.199.62.198];Helo=[xsj-pvapexch01.xlnx.xilinx.com] X-MS-Exchange-CrossTenant-AuthSource: DM3NAM02FT021.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH0PR02MB7589 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org ICAP stands for Hardware Internal Configuration Access Port. ICAP is discovered by walking the firmware metadata. A xrt device node will be created for it. FPGA bitstream is written to hardware through ICAP. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Reviewed-by: Tom Rix --- drivers/fpga/xrt/include/xleaf/icap.h | 27 +++ drivers/fpga/xrt/lib/xleaf/icap.c | 328 ++++++++++++++++++++++++++ 2 files changed, 355 insertions(+) create mode 100644 drivers/fpga/xrt/include/xleaf/icap.h create mode 100644 drivers/fpga/xrt/lib/xleaf/icap.c diff --git a/drivers/fpga/xrt/include/xleaf/icap.h b/drivers/fpga/xrt/include/xleaf/icap.h new file mode 100644 index 000000000000..96d39a8934fa --- /dev/null +++ b/drivers/fpga/xrt/include/xleaf/icap.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#ifndef _XRT_ICAP_H_ +#define _XRT_ICAP_H_ + +#include "xleaf.h" + +/* + * ICAP driver leaf calls. + */ +enum xrt_icap_leaf_cmd { + XRT_ICAP_WRITE = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */ + XRT_ICAP_GET_IDCODE, +}; + +struct xrt_icap_wr { + void *xiiw_bit_data; + u32 xiiw_data_len; +}; + +#endif /* _XRT_ICAP_H_ */ diff --git a/drivers/fpga/xrt/lib/xleaf/icap.c b/drivers/fpga/xrt/lib/xleaf/icap.c new file mode 100644 index 000000000000..071923f61537 --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/icap.c @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA ICAP Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + * Sonal Santan + * Max Zhen + */ + +#include +#include +#include +#include +#include +#include "metadata.h" +#include "xleaf.h" +#include "xleaf/icap.h" +#include "xclbin-helper.h" + +#define XRT_ICAP "xrt_icap" + +#define ICAP_ERR(icap, fmt, arg...) \ + xrt_err((icap)->xdev, fmt "\n", ##arg) +#define ICAP_WARN(icap, fmt, arg...) \ + xrt_warn((icap)->xdev, fmt "\n", ##arg) +#define ICAP_INFO(icap, fmt, arg...) \ + xrt_info((icap)->xdev, fmt "\n", ##arg) +#define ICAP_DBG(icap, fmt, arg...) \ + xrt_dbg((icap)->xdev, fmt "\n", ##arg) + +/* + * AXI-HWICAP IP register layout. Please see + * https://www.xilinx.com/support/documentation/ip_documentation/axi_hwicap/v3_0/pg134-axi-hwicap.pdf + */ +#define ICAP_REG_GIER 0x1C +#define ICAP_REG_ISR 0x20 +#define ICAP_REG_IER 0x28 +#define ICAP_REG_WF 0x100 +#define ICAP_REG_RF 0x104 +#define ICAP_REG_SZ 0x108 +#define ICAP_REG_CR 0x10C +#define ICAP_REG_SR 0x110 +#define ICAP_REG_WFV 0x114 +#define ICAP_REG_RFO 0x118 +#define ICAP_REG_ASR 0x11C + +#define ICAP_STATUS_EOS 0x4 +#define ICAP_STATUS_DONE 0x1 + +/* + * Canned command sequence to obtain IDCODE of the FPGA + */ +static const __be32 idcode_stream[] = { + /* dummy word */ + cpu_to_be32(0xffffffff), + /* sync word */ + cpu_to_be32(0xaa995566), + /* NOP word */ + cpu_to_be32(0x20000000), + /* NOP word */ + cpu_to_be32(0x20000000), + /* ID code */ + cpu_to_be32(0x28018001), + /* NOP word */ + cpu_to_be32(0x20000000), + /* NOP word */ + cpu_to_be32(0x20000000), +}; + +XRT_DEFINE_REGMAP_CONFIG(icap_regmap_config); + +struct icap { + struct xrt_device *xdev; + struct regmap *regmap; + struct mutex icap_lock; /* icap dev lock */ + u32 idcode; +}; + +static int wait_for_done(const struct icap *icap) +{ + int i = 0; + int ret; + u32 w; + + for (i = 0; i < 10; i++) { + /* + * it requires few micro seconds for ICAP to process incoming data. + * Polling every 5us for 10 times would be good enough. + */ + udelay(5); + ret = regmap_read(icap->regmap, ICAP_REG_SR, &w); + if (ret) + return ret; + ICAP_INFO(icap, "XHWICAP_SR: %x", w); + if (w & (ICAP_STATUS_EOS | ICAP_STATUS_DONE)) + return 0; + } + + ICAP_ERR(icap, "bitstream download timeout"); + return -ETIMEDOUT; +} + +static int icap_write(const struct icap *icap, const __be32 *word_buf, int size) +{ + u32 value = 0; + int ret; + int i; + + for (i = 0; i < size; i++) { + value = be32_to_cpu(word_buf[i]); + ret = regmap_write(icap->regmap, ICAP_REG_WF, value); + if (ret) + return ret; + } + + ret = regmap_write(icap->regmap, ICAP_REG_CR, 0x1); + if (ret) + return ret; + + for (i = 0; i < 20; i++) { + ret = regmap_read(icap->regmap, ICAP_REG_CR, &value); + if (ret) + return ret; + + if ((value & 0x1) == 0) + return 0; + ndelay(50); + } + + ICAP_ERR(icap, "writing %d dwords timeout", size); + return -EIO; +} + +static int bitstream_helper(struct icap *icap, const __be32 *word_buffer, + u32 word_count) +{ + int wr_fifo_vacancy = 0; + u32 word_written = 0; + u32 remain_word; + int err = 0; + + WARN_ON(!mutex_is_locked(&icap->icap_lock)); + for (remain_word = word_count; remain_word > 0; + remain_word -= word_written, word_buffer += word_written) { + err = regmap_read(icap->regmap, ICAP_REG_WFV, &wr_fifo_vacancy); + if (err) { + ICAP_ERR(icap, "read wr_fifo_vacancy failed %d", err); + break; + } + if (wr_fifo_vacancy <= 0) { + ICAP_ERR(icap, "no vacancy: %d", wr_fifo_vacancy); + err = -EIO; + break; + } + word_written = (wr_fifo_vacancy < remain_word) ? + wr_fifo_vacancy : remain_word; + if (icap_write(icap, word_buffer, word_written) != 0) { + ICAP_ERR(icap, "write failed remain %d, written %d", + remain_word, word_written); + err = -EIO; + break; + } + } + + return err; +} + +static int icap_download(struct icap *icap, const char *buffer, + unsigned long length) +{ + u32 num_chars_read = XCLBIN_HWICAP_BITFILE_BUF_SZ; + u32 byte_read; + int err = 0; + + if (length % sizeof(u32)) { + ICAP_ERR(icap, "invalid bitstream length %ld", length); + return -EINVAL; + } + + mutex_lock(&icap->icap_lock); + for (byte_read = 0; byte_read < length; byte_read += num_chars_read) { + num_chars_read = length - byte_read; + if (num_chars_read > XCLBIN_HWICAP_BITFILE_BUF_SZ) + num_chars_read = XCLBIN_HWICAP_BITFILE_BUF_SZ; + + err = bitstream_helper(icap, (__be32 *)buffer, num_chars_read / sizeof(u32)); + if (err) + goto failed; + buffer += num_chars_read; + } + + /* there is not any cleanup needs to be done if writing ICAP timeout. */ + err = wait_for_done(icap); + +failed: + mutex_unlock(&icap->icap_lock); + + return err; +} + +/* + * Discover the FPGA IDCODE using special sequence of canned commands + */ +static int icap_probe_chip(struct icap *icap) +{ + int err; + u32 val = 0; + + regmap_read(icap->regmap, ICAP_REG_SR, &val); + if (val != ICAP_STATUS_DONE) + return -ENODEV; + /* Read ICAP FIFO vacancy */ + regmap_read(icap->regmap, ICAP_REG_WFV, &val); + if (val < 8) + return -ENODEV; + err = icap_write(icap, idcode_stream, ARRAY_SIZE(idcode_stream)); + if (err) + return err; + err = wait_for_done(icap); + if (err) + return err; + + /* Tell config engine how many words to transfer to read FIFO */ + regmap_write(icap->regmap, ICAP_REG_SZ, 0x1); + /* Switch the ICAP to read mode */ + regmap_write(icap->regmap, ICAP_REG_CR, 0x2); + err = wait_for_done(icap); + if (err) + return err; + + /* Read IDCODE from Read FIFO */ + regmap_read(icap->regmap, ICAP_REG_RF, &icap->idcode); + return 0; +} + +static int +xrt_icap_leaf_call(struct xrt_device *xdev, u32 cmd, void *arg) +{ + struct xrt_icap_wr *wr_arg = arg; + struct icap *icap; + int ret = 0; + + icap = xrt_get_drvdata(xdev); + + switch (cmd) { + case XRT_XLEAF_EVENT: + /* Does not handle any event. */ + break; + case XRT_ICAP_WRITE: + ret = icap_download(icap, wr_arg->xiiw_bit_data, + wr_arg->xiiw_data_len); + break; + case XRT_ICAP_GET_IDCODE: + *(u32 *)arg = icap->idcode; + break; + default: + ICAP_ERR(icap, "unknown command %d", cmd); + return -EINVAL; + } + + return ret; +} + +static int xrt_icap_probe(struct xrt_device *xdev) +{ + void __iomem *base = NULL; + struct resource *res; + struct icap *icap; + int result = 0; + + icap = devm_kzalloc(&xdev->dev, sizeof(*icap), GFP_KERNEL); + if (!icap) + return -ENOMEM; + + icap->xdev = xdev; + xrt_set_drvdata(xdev, icap); + mutex_init(&icap->icap_lock); + + xrt_info(xdev, "probing"); + res = xrt_get_resource(xdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + base = devm_ioremap_resource(&xdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + icap->regmap = devm_regmap_init_mmio(&xdev->dev, base, &icap_regmap_config); + if (IS_ERR(icap->regmap)) { + ICAP_ERR(icap, "init mmio failed"); + return PTR_ERR(icap->regmap); + } + /* Disable ICAP interrupts */ + regmap_write(icap->regmap, ICAP_REG_GIER, 0); + + result = icap_probe_chip(icap); + if (result) + xrt_err(xdev, "Failed to probe FPGA"); + else + xrt_info(xdev, "Discovered FPGA IDCODE %x", icap->idcode); + return result; +} + +static struct xrt_dev_endpoints xrt_icap_endpoints[] = { + { + .xse_names = (struct xrt_dev_ep_names[]) { + { .ep_name = XRT_MD_NODE_FPGA_CONFIG }, + { NULL }, + }, + .xse_min_ep = 1, + }, + { 0 }, +}; + +static struct xrt_driver xrt_icap_driver = { + .driver = { + .name = XRT_ICAP, + }, + .subdev_id = XRT_SUBDEV_ICAP, + .endpoints = xrt_icap_endpoints, + .probe = xrt_icap_probe, + .leaf_call = xrt_icap_leaf_call, +}; + +XRT_LEAF_INIT_FINI_FUNC(icap); -- 2.27.0