From e29e5689e0c59bcfd5341a1192c57169a10dc18a Mon Sep 17 00:00:00 2001 From: Kedareswara rao Appana Date: Thu, 16 Oct 2014 12:44:02 +0530 Subject: [PATCH] mcap: Add MCAP Linux Library The MCAP interface enables an embedded microprocessor, such as MicroBlaze, to read and write the FPGA configuration memory. This library allows user to access the MCAP i/f. Signed-off-by: Srikanth Thokala Signed-off-by: Kedareswara rao Appana --- README.txt | 30 ++- mcap/linux/Makefile | 35 +++ mcap/linux/README | 56 ++++ mcap/linux/mcap.c | 167 ++++++++++++ mcap/linux/mcap_lib.c | 611 ++++++++++++++++++++++++++++++++++++++++++ mcap/linux/mcap_lib.h | 158 +++++++++++ 6 files changed, 1045 insertions(+), 12 deletions(-) create mode 100644 mcap/linux/Makefile create mode 100644 mcap/linux/README create mode 100644 mcap/linux/mcap.c create mode 100644 mcap/linux/mcap_lib.c create mode 100644 mcap/linux/mcap_lib.h diff --git a/README.txt b/README.txt index 1cc75ee9..5a35ebc3 100644 --- a/README.txt +++ b/README.txt @@ -6,12 +6,15 @@ All software is version less and divided into three directories - license.txt contains information about the various licenses and copyrights - XilinxProcessorIPLib - contains all drivers - - ThirdParty - software from third party like light weight IP stack - -Every driver/lib/apps/services has these sub-directories - + contains all drivers + - ThirdParty + software from third party like light weight IP stack + - mcap + software for using MCAP interface on Ultra Scale boards to + program 2nd level bitstream + +Every driver/lib/apps/services has these sub-directories + 1. data - contains tcl, mdd, testapp tcl or header files used in SDK 2. doc - documentation of source code in form of pdf or html 3. examples - illustrating different use cases of driver @@ -53,12 +56,15 @@ Every driver/lib/apps/services has these sub-directories | | Note - All these are libraries and utilize drivers | -|-ThirdParty -| |- sw_services -| |- lwip140 - - -Building FSBL from git: +|-ThirdParty +| |- sw_services +| |- lwip140 +| +|-mcap +| |-linux + + +Building FSBL from git: FSBL has 3 directories. 1. data - It contains files for SDK diff --git a/mcap/linux/Makefile b/mcap/linux/Makefile new file mode 100644 index 00000000..8b216bba --- /dev/null +++ b/mcap/linux/Makefile @@ -0,0 +1,35 @@ +# Makefile for Xilinx MCAP Interface Library +# (c) 2014 Xilinx Inc. + +PCIUTILS_PATH = + +PCILIB_PATH=$(PCIUTILS_PATH)/lib/ + +INCLUDES = -I$(PCILIB_PATH) -I$(PCIUTILS_PATH) -I. + +OPT=-O2 +CFLAGS=$(OPT) -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) + +LDFLAGS = -L$(PCILIB_PATH) +LDLIBS = -lpci + +PCILIB = $(PCILIB_PATH)/libpci.a + +MCAPLIB = libmcap.a +MCAPINC = mcap_lib.h + +OBJ = mcap_lib.o + +all: $(MCAPLIB) mcap + +$(MCAPLIB): $(OBJ) + ar rcs $(MCAPLIB) $(OBJ) + +$(OBJ): + gcc $(LDFLAGS) $(CFLAGS) -c mcap_lib.c $< -o $@ $(LDLIBS) + +mcap: mcap.o + gcc $(CFLAGS) mcap.c $(MCAPLIB) $(PCILIB) -lz -o mcap + +clean: + rm -f *.o *.a mcap diff --git a/mcap/linux/README b/mcap/linux/README new file mode 100644 index 00000000..76f50c5d --- /dev/null +++ b/mcap/linux/README @@ -0,0 +1,56 @@ +Steps to compile +################ +1. Download the latest PCI Utilites source from + https://www.kernel.org/pub/software/utils/pciutils/ + + (Or) Source can be clone from the GIT repository, + http://git.kernel.org/cgit/utils/pciutils/pciutils.git/ + +2. Compile the PCI Utilities by the following command, + $pci-utils> make + +3. Compile the MCAP Library by the following make command, + $mcap-lib> make PCIUTILS_PATH= + +4. Compiling the MCAP library generates 'libmcap.a' and + example elf 'mcap' built on top of generated library. + +Steps to Run +############ +-> Running the 'mcap.elf' with '-h' lists all the options + that are available to communicate with the underlying + MCAP device, + $Linux> ./mcap -h + Usage: mcap [options] + + Options: + -x Specify MCAP Device ID in hex (Mandatory) + -p Program Bitstream (.bin/.bit/.rbt) + -r Performs Simple Reset + -m Performs Module Reset + -f Performs Full Reset + -D Read Data Registers + -d Dump all the MCAP Registers + -v Verbose information of MCAP Device + -h/H Help + -c
[type [data]] Access Device Configuration Space + + NOTE: Specifying MCAP Device Id option is mandatory for the application + to run. For example, + $Linux> ./mcap -x 0x8011 + Xilinx MCAP Device Found + +NOTES +##### +. PCI Extended Capability Registers in Linux will only be + accessible with privileged user access. So, the example elf should + be run with ROOT permissions. + +. To access device configuration space, 'type' in the above syntax should + be either b/h/w (byte/half-word/word). For example, + + -> Reading a byte + ./mcap -x 0x8011 -c 0x354 b + + -> Writing a word + ./mcap -x 0x8011 -c 0x354 w 0x3 diff --git a/mcap/linux/mcap.c b/mcap/linux/mcap.c new file mode 100644 index 00000000..366605e5 --- /dev/null +++ b/mcap/linux/mcap.c @@ -0,0 +1,167 @@ +/****************************************************************************** +* Copyright (C) 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file mcap.c +* MCAP Interface Library Test Application +* +******************************************************************************/ + +#include "mcap_lib.h" + +static const char options[] = "x:p:rmfdvHhDc::"; +static char help_msg[] = +"Usage: mcap [options]\n" +"\n" +"Options:\n" +"\t-x\t\tSpecify MCAP Device Id in hex (MANDATORY)\n" +"\t-p \tProgram Bitstream (.bin/.bit/.rbt)\n" +"\t-r\t\tPerforms Simple Reset\n" +"\t-m\t\tPerforms Module Reset\n" +"\t-f\t\tPerforms Full Reset\n" +"\t-D\t\tRead Data Registers\n" +"\t-d\t\tDump all the MCAP Registers\n" +"\t-v\t\tVerbose information of MCAP Device\n" +"\t-h/H\t\tHelp\n" +"\t-c
[type [data]] Access Device Configuration Space\n" +"\n" +; + +int main(int argc, char **argv) +{ + struct mcap_dev *mdev; + int i, modreset = 0, fullreset = 0, reset = 0; + int program = 0, verbose = 0, device_id = 0; + int data_regs = 0, dump_regs = 0, access_config = 0; + + while ((i = getopt(argc, argv, options)) != -1) { + switch (i) { + case 'c': + access_config = 1; + break; + case 'd': + dump_regs = 1; + break; + case 'm': + modreset = 1; + break; + case 'f': + fullreset = 1; + break; + case 'r': + reset = 1; + break; + case 'D': + data_regs = 1; + break; + case 'h': + case 'H': + printf("%s", help_msg); + return 1; + case 'p': + program = 1; + break; + case 'v': + verbose++; + break; + case 'x': + device_id = (int) strtol(argv[2], NULL, 16); + break; + default: + printf("%s", help_msg); + return 1; + } + } + + if (!device_id) { + printf("No device id specified...\n"); + printf("%s", help_msg); + return 1; + } + + mdev = (struct mcap_dev *)MCapLibInit(device_id); + if (!mdev) + return 1; + + if (verbose) { + MCapShowDevice(mdev, verbose); + goto free; + } + + if (access_config) { + if (argc < 6) { + printf("%s", help_msg); + goto free; + } + if (MCapAccessConfigSpace(mdev, argc, argv)) + printf("%s", help_msg); + goto free; + } + + if (fullreset) { + MCapFullReset(mdev); + goto free; + } + + if (modreset) { + MCapModuleReset(mdev); + goto free; + } + + if (reset) { + MCapReset(mdev); + goto free; + } + + if (program) { + MCapConfigureFPGA(mdev, argv[4]); + goto free; + } + + if (dump_regs) { + MCapDumpRegs(mdev); + goto free; + } + + if (data_regs) { + MCapDumpReadRegs(mdev); + goto free; + } + + if (i == -1 && argc == 1) + MCapShowDevice(mdev, 0); + +free: + MCapLibFree(mdev); + + return 0; +} diff --git a/mcap/linux/mcap_lib.c b/mcap/linux/mcap_lib.c new file mode 100644 index 00000000..bfe8a910 --- /dev/null +++ b/mcap/linux/mcap_lib.c @@ -0,0 +1,611 @@ +/****************************************************************************** +* Copyright (C) 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file mcap_lib.c +* MCAP Interface Library functions +* +******************************************************************************/ + +#include "mcap_lib.h" + +/* Library Specific Definitions */ +#define MCAP_VENDOR_ID 0x10EE + +#define MCAP_LOOP_COUNT 1000000 + +#define MCAP_SYNC_DWORD 0xaa995566 +#define MCAP_SYNC_BYTE0 ((MCAP_SYNC_DWORD & 0xFF000000) >> 24) +#define MCAP_SYNC_BYTE1 ((MCAP_SYNC_DWORD & 0x00FF0000) >> 16) +#define MCAP_SYNC_BYTE2 ((MCAP_SYNC_DWORD & 0x0000FF00) >> 8) +#define MCAP_SYNC_BYTE3 ((MCAP_SYNC_DWORD & 0x000000FF) >> 0) + +#define MCAP_RBT_FILE ".rbt" +#define MCAP_BIT_FILE ".bit" +#define MCAP_BIN_FILE ".bin" + +static char *MCapFindTypeofFile(const char *s1, const char *s2) +{ + size_t l1, l2; + + l2 = strlen(s2); + if (!l2) + return (char *)s1; + l1 = strlen(s1); + while (l1 >= l2) { + l1--; + if (!strncasecmp(s1, s2, l2)) + return (char *)s1; + s1++; + } + + return NULL; +} + +static u32 MCapProcessRBT(FILE *fptr, u32 *buf) +{ + char *raw = NULL; + int i, read; + size_t linelen; + u32 count = 0, len = 0, result = 0; + + while ((read = getline(&raw, &linelen, fptr)) != -1) { + if (raw[0] == '/' && raw[1] == '/') + continue; + + for (i = 0; i < read - 1; i++) { + if (raw[i] == '1' || raw[i] == '0') { + result = (result << 1) | (raw[i] - 0x30); + count++; + if (count == 32) { + *buf++ = result; + len += 4; + result = count = 0; + break; + } + } + } + } + + return len/4; +} + +static u32 MCapProcessBIT(FILE *fptr, u32 *buf, int sz) +{ + int err; + u8 value, len = 0; + + /* + * .bit files are not guaranteed to be aligned with + * the bitstream sync word on a 32-bit boundary. So, + * we need to check every byte here. + */ + while ((err = fread(&value, 1, 1, fptr)) == 1) { + if (value == MCAP_SYNC_BYTE0) + if ((err = fread(&value, 1, 1, fptr)) == 1) + if (value == MCAP_SYNC_BYTE1) + if ((err = fread(&value, 1, 1, fptr)) == 1) + if (value == MCAP_SYNC_BYTE2) + if ((err = fread(&value, 1, 1, fptr)) == 1) + if (value == MCAP_SYNC_BYTE3) + break; + } + + if (err != 1 && !feof(fptr)) { + pr_err("Failed to Read BIT file\n"); + return 0; + } + + if (err != 1 && feof(fptr)) { + pr_err("Failed to find SYNC Word in BIT file\n"); + return 0; + } + + *buf++ = __bswap_32(MCAP_SYNC_DWORD); + len += 4; + + while ((err = fread(buf, sz - len, 1, fptr)) == 1) + ; + + if (err != 1 && !feof(fptr)) { + pr_err("Failed to Read BIT file\n"); + return 0; + } + + return (sz - len)/4; +} + +static u32 MCapProcessBIN(FILE *fptr, u32 *buf, int sz) +{ + int err; + + err = fread(buf, sz, 1, fptr); + if (err != 1 && !feof(fptr)) { + pr_err("Failed to Read BIN file\n"); + return 0; + } + + return sz/4; +} + +static int MCapDoBusWalk(struct mcap_dev *mdev) +{ + struct pci_cap *c; + + c = pci_find_cap(mdev->pdev, MCAP_EXT_CAP_ID, PCI_CAP_EXTENDED); + + if (!c) + return -EMCAPBUSWALK; + + mdev->reg_base = c->addr; + + return 0; +} + +static int MCapClearRequestByConfigure(struct mcap_dev *mdev, u32 *restore) +{ + u32 set; + int loop = MCAP_LOOP_COUNT; + + set = *restore = MCapRegRead(mdev, MCAP_CONTROL); + + if (IsConfigureMCapReqSet(mdev)) { + /* Set 'Mode' and 'In Use by PCIe' bits */ + set |= (MCAP_CTRL_MODE_MASK | MCAP_CTRL_IN_USE_MASK); + MCapRegWrite(mdev, MCAP_CONTROL, set); + + do { + if (!(IsConfigureMCapReqSet(mdev))) + break; + } while (loop--); + + if (!loop) { + pr_err("Failed to clear MCAP Request by config bit\n"); + MCapRegWrite(mdev, MCAP_CONTROL, *restore); + return -EMCAPREQ; + } + } + + pr_dbg("Request by Configure bit cleared!!\n"); + + return 0; +} + +static int MCapWriteBitStream(struct mcap_dev *mdev, u32 *data, + int len, u8 bswap) +{ + u32 set, restore; + int err, count = 0; + + if (!data || !len) { + pr_err("Invalid Arguments\n"); + return -EMCAPWRITE; + } + + err = MCapClearRequestByConfigure(mdev, &restore); + if (err) + return err; + + if (IsErrSet(mdev) || IsRegReadComplete(mdev) || + IsFifoOverflow(mdev)) { + pr_err("Failed to initialize configuring FPGA\n"); + MCapRegWrite(mdev, MCAP_CONTROL, restore); + return -EMCAPWRITE; + } + + /* Set 'Mode', 'In Use by PCIe' and 'Data Reg Protect' bits */ + set = MCapRegRead(mdev, MCAP_CONTROL); + set |= MCAP_CTRL_MODE_MASK | MCAP_CTRL_IN_USE_MASK | + MCAP_CTRL_DATA_REG_PROT_MASK; + + /* Clear 'Reset', 'Module Reset' and 'Register Read' bits */ + set &= ~(MCAP_CTRL_RESET_MASK | MCAP_CTRL_MOD_RESET_MASK | + MCAP_CTRL_REG_READ_MASK | MCAP_CTRL_DESIGN_SWITCH_MASK); + + MCapRegWrite(mdev, MCAP_CONTROL, set); + + /* Write Data */ + if (!bswap) { + for (count = 0; count < len; count++) + MCapRegWrite(mdev, MCAP_DATA, data[count]); + } else { + for (count = 0; count < len; count++) + MCapRegWrite(mdev, MCAP_DATA, __bswap_32(data[count])); + } + + if (IsErrSet(mdev) || IsFifoOverflow(mdev)) { + pr_err("Failed to Write Bitstream\n"); + MCapRegWrite(mdev, MCAP_CONTROL, restore); + return -EMCAPWRITE; + } + + /* Enable PCIe BAR reads/writes in the PCIe hardblock */ + restore |= MCAP_CTRL_DESIGN_SWITCH_MASK; + + MCapRegWrite(mdev, MCAP_CONTROL, restore); + + return 0; +} + +void MCapLibFree(struct mcap_dev *mdev) +{ + if (mdev) { + pci_cleanup(mdev->pacc); + free(mdev); + } +} + +struct mcap_dev *MCapLibInit(int device_id) +{ + struct pci_dev *dev; + struct mcap_dev *mdev; + + /* Allocate MCAP device */ + mdev = malloc(sizeof(struct mcap_dev)); + if (!mdev) + return NULL; + + /* Get the pci_access structure */ + mdev->pacc = pci_alloc(); + + /* Initialize the PCI library */ + pci_init(mdev->pacc); + + /* Get the list of devices */ + pci_scan_bus(mdev->pacc); + + for (dev = mdev->pacc->devices; dev; dev = dev->next) { + /* Fill in header info we need */ + pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | + PCI_FILL_CLASS); + + if (dev->vendor_id == MCAP_VENDOR_ID && + dev->device_id == device_id) { + pr_info("Xilinx MCAP device found\n"); + mdev->pdev = dev; + } else { + continue; + } + } + + if (!mdev->pdev) { + pr_err("Xilinx MCAP device not found .. Exiting ...\n"); + goto free_resources; + } + + /* Get the MCAP Register base */ + if (MCapDoBusWalk(mdev)) { + pr_err("Unable to get the Register Base\n"); + goto free_resources; + } + + return mdev; + +free_resources: + MCapLibFree(mdev); + + return NULL; +} + +int MCapReset(struct mcap_dev *mdev) +{ + u32 set, restore; + int err; + + err = MCapClearRequestByConfigure(mdev, &restore); + if (err) + return err; + + /* Set 'Mode', 'In Use by PCIe' and 'Reset' bits */ + set = MCapRegRead(mdev, MCAP_CONTROL); + set |= MCAP_CTRL_MODE_MASK | MCAP_CTRL_IN_USE_MASK | + MCAP_CTRL_RESET_MASK; + MCapRegWrite(mdev, MCAP_CONTROL, set); + + if (IsErrSet(mdev) || !(IsResetSet(mdev))) { + pr_err("Failed to Reset\n"); + MCapRegWrite(mdev, MCAP_CONTROL, restore); + return -EMCAPRESET; + } + + MCapRegWrite(mdev, MCAP_CONTROL, restore); + pr_info("Reset Done!!\n"); + + return 0; +} + +int MCapModuleReset(struct mcap_dev *mdev) +{ + u32 set, restore; + int err; + + err = MCapClearRequestByConfigure(mdev, &restore); + if (err) + return err; + + /* Set 'Mode', 'In Use by PCIe' and 'Module Reset' bits */ + set = MCapRegRead(mdev, MCAP_CONTROL); + set |= MCAP_CTRL_MODE_MASK | MCAP_CTRL_IN_USE_MASK | + MCAP_CTRL_MOD_RESET_MASK; + MCapRegWrite(mdev, MCAP_CONTROL, set); + + if (IsErrSet(mdev) || !(IsModuleResetSet(mdev))) { + pr_err("Failed to Reset Module\n"); + MCapRegWrite(mdev, MCAP_CONTROL, restore); + return -EMCAPMODRESET; + } + + MCapRegWrite(mdev, MCAP_CONTROL, restore); + pr_info("Module Reset Done!!\n"); + + return 0; +} + +int MCapFullReset(struct mcap_dev *mdev) +{ + u32 set, restore; + int err; + + err = MCapClearRequestByConfigure(mdev, &restore); + if (err) + return err; + + /* Set 'Mode', 'In Use by PCIe' and 'Module Reset' bits */ + set = MCapRegRead(mdev, MCAP_CONTROL); + set |= MCAP_CTRL_MODE_MASK | MCAP_CTRL_IN_USE_MASK | + MCAP_CTRL_RESET_MASK | MCAP_CTRL_MOD_RESET_MASK; + MCapRegWrite(mdev, MCAP_CONTROL, set); + + if (IsErrSet(mdev) || !(IsModuleResetSet(mdev)) || + !(IsResetSet(mdev))) { + pr_err("Failed to Full Reset\n"); + MCapRegWrite(mdev, MCAP_CONTROL, restore); + return -EMCAPFULLRESET; + } + + MCapRegWrite(mdev, MCAP_CONTROL, restore); + pr_info("Full Reset Done!!\n"); + + return 0; +} + +static int MCapReadDataRegisters(struct mcap_dev *mdev, u32 *data) +{ + u32 set, restore, read_cnt; + int err; + + if (!data) { + pr_err("Invalid Arguments\n"); + return -EMCAPREAD; + } + + err = MCapClearRequestByConfigure(mdev, &restore); + if (err) + return err; + + /* Set 'Mode', 'In Use by PCIe' and 'Data Reg Protect' bits */ + set = MCapRegRead(mdev, MCAP_CONTROL); + set |= MCAP_CTRL_MODE_MASK | MCAP_CTRL_IN_USE_MASK | + MCAP_CTRL_REG_READ_MASK; + + /* Clear 'Reset', 'Module Reset' and 'Register Read' bits */ + set &= ~(MCAP_CTRL_RESET_MASK | MCAP_CTRL_MOD_RESET_MASK); + + MCapRegWrite(mdev, MCAP_CONTROL, set); + read_cnt = GetRegReadCount(mdev); + + if (IsErrSet(mdev) || IsFifoOverflow(mdev) || + !(read_cnt) || !(IsRegReadComplete(mdev))) { + pr_err("Read Register Set Configuration Failed\n"); + MCapRegWrite(mdev, MCAP_CONTROL, restore); + return -EMCAPREAD; + } + + switch (read_cnt) { + case 7: case 6: case 5: case 4: + data[3] = MCapRegRead(mdev, MCAP_READ_DATA_3); + /* Fall-through */ + case 3: + data[2] = MCapRegRead(mdev, MCAP_READ_DATA_2); + /* Fall-through */ + case 2: + data[1] = MCapRegRead(mdev, MCAP_READ_DATA_1); + /* Fall-through */ + case 1: + data[0] = MCapRegRead(mdev, MCAP_READ_DATA_0); + break; + } + + MCapRegWrite(mdev, MCAP_CONTROL, restore); + pr_dbg("Read Data Registers Complete!\n"); + + return 0; +} + +void MCapDumpReadRegs(struct mcap_dev *mdev) +{ + u32 data[4]; + + if (MCapReadDataRegisters(mdev, data)) { + pr_err("Failed Reading Registers.. This may be"); + pr_err("due to inappropriate FPGA configuration."); + pr_err("Make sure you downloaded the correct bitstream\n"); + return; + } + pr_info("Register Read Data 0:\t0x%08x\n", data[0]); + pr_info("Register Read Data 1:\t0x%08x\n", data[1]); + pr_info("Register Read Data 2:\t0x%08x\n", data[2]); + pr_info("Register Read Data 3:\t0x%08x\n", data[3]); +} + +void MCapDumpRegs(struct mcap_dev *mdev) +{ + pr_info("Extended Capability:\t0x%08x\n", + MCapRegRead(mdev, MCAP_EXT_CAP_HEADER)); + pr_info("Vendor Specific Header:\t0x%08x\n", + MCapRegRead(mdev, MCAP_VEND_SPEC_HEADER)); + pr_info("FPGA JTAG ID:\t\t0x%08x\n", + MCapRegRead(mdev, MCAP_FPGA_JTAG_ID)); + pr_info("FPGA Bit-Stream Version:0x%08x\n", + MCapRegRead(mdev, MCAP_FPGA_BIT_VERSION)); + pr_info("Status:\t\t\t0x%08x\n", + MCapRegRead(mdev, MCAP_STATUS)); + pr_info("Control:\t\t0x%08x\n", + MCapRegRead(mdev, MCAP_CONTROL)); + pr_info("Data:\t\t\t0x%08x\n", + MCapRegRead(mdev, MCAP_DATA)); + + MCapDumpReadRegs(mdev); +} + +int MCapConfigureFPGA(struct mcap_dev *mdev, char *file_path) +{ + FILE *fptr; + u32 *data; + u32 binsz, wrdatasz; + int err = 0; + u8 bswap = 0; + + /* Get the size */ + fptr = fopen(file_path, "rb"); + if (fptr == NULL) + return -EMCAPCFG; + fseek(fptr, 0L, SEEK_END); + binsz = ftell(fptr); + fseek(fptr, 0L, SEEK_SET); + + /* Allocate the buffer */ + data = malloc(binsz); + if (data == NULL) + return -EMCAPCFG; + + /* Process files and Read the data */ + if (MCapFindTypeofFile(file_path, MCAP_RBT_FILE)) { + + /* Read the RBT file */ + wrdatasz = MCapProcessRBT(fptr, data); + + } else if (MCapFindTypeofFile(file_path, MCAP_BIT_FILE)) { + + /* Read the BIT file */ + wrdatasz = MCapProcessBIT(fptr, data, binsz); + bswap = 1; + + } else if (MCapFindTypeofFile(file_path, MCAP_BIN_FILE)) { + + /* Read the BIN file */ + wrdatasz = MCapProcessBIN(fptr, data, binsz); + bswap = 1; + + } else { + pr_err("Unknown File Format\n"); + goto free_resources; + } + + /* Program FPGA */ + err = MCapWriteBitStream(mdev, data, wrdatasz, bswap); + if (err) + return -EMCAPCFG; + + pr_info("FPGA Configuration Done!!\n"); + +free_resources: + if (data) + free(data); + fclose(fptr); + + return err; +} + +int MCapAccessConfigSpace(struct mcap_dev *mdev, int argc, char **argv) +{ + unsigned long wrval, rdval; + int pos, access_type; + + pos = (int) strtol(argv[4], NULL, 16); + access_type = tolower(argv[5][0]); + + if (argc == 6) { + switch (access_type) { + case 'b': + rdval = pci_read_byte(mdev->pdev, pos); + break; + case 'h': + rdval = pci_read_word(mdev->pdev, pos); + break; + case 'w': + rdval = pci_read_long(mdev->pdev, pos); + break; + default: + return -EMCAPCFGACC; + } + pr_info("Read 0x%08lx @ 0x%x\n", rdval, pos); + } + + if (argc > 6) { + wrval = strtoul(argv[6], 0, 0); + switch (access_type) { + case 'b': + pci_write_byte(mdev->pdev, pos, wrval); + break; + case 'h': + pci_write_word(mdev->pdev, pos, wrval); + break; + case 'w': + pci_write_long(mdev->pdev, pos, wrval); + break; + default: + return -EMCAPCFGACC; + } + pr_info("Written 0x%08lx @ 0x%x\n", wrval, pos); + } + + return 0; +} + +int MCapShowDevice(struct mcap_dev *mdev, int verbose) +{ + char command[80]; + u16 vendor_id, device_id; + + vendor_id = mdev->pdev->vendor_id; + device_id = mdev->pdev->device_id; + + if (verbose == 1) + sprintf(command, "lspci -vd %x:%x", vendor_id, device_id); + if (verbose >= 2) + sprintf(command, "lspci -vvd %x:%x", vendor_id, device_id); + if (!verbose) + sprintf(command, "lspci -d %x:%x", vendor_id, device_id); + + return system(command); +} diff --git a/mcap/linux/mcap_lib.h b/mcap/linux/mcap_lib.h new file mode 100644 index 00000000..b1b8ca72 --- /dev/null +++ b/mcap/linux/mcap_lib.h @@ -0,0 +1,158 @@ +/****************************************************************************** +* Copyright (C) 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file mcap_lib.h +* MCAP Interface Library support header file +* +******************************************************************************/ + +#include +#include +#include +#include +#include + +#include "pci.h" +#include "lspci.h" +#include "byteswap.h" + +/* Register Definitions */ +#define MCAP_EXT_CAP_HEADER 0x00 +#define MCAP_VEND_SPEC_HEADER 0x04 +#define MCAP_FPGA_JTAG_ID 0x08 +#define MCAP_FPGA_BIT_VERSION 0x0C +#define MCAP_STATUS 0x10 +#define MCAP_CONTROL 0x14 +#define MCAP_DATA 0x18 +#define MCAP_READ_DATA_0 0x1C +#define MCAP_READ_DATA_1 0x20 +#define MCAP_READ_DATA_2 0x24 +#define MCAP_READ_DATA_3 0x28 + +#define MCAP_CTRL_MODE_MASK (1 << 0) +#define MCAP_CTRL_REG_READ_MASK (1 << 1) +#define MCAP_CTRL_RESET_MASK (1 << 4) +#define MCAP_CTRL_MOD_RESET_MASK (1 << 5) +#define MCAP_CTRL_IN_USE_MASK (1 << 8) +#define MCAP_CTRL_DESIGN_SWITCH_MASK (1 << 12) +#define MCAP_CTRL_DATA_REG_PROT_MASK (1 << 16) + +#define MCAP_STS_ERR_MASK (1 << 0) +#define MCAP_STS_EOS_MASK (1 << 1) +#define MCAP_STS_REG_READ_CMP_MASK (1 << 4) +#define MCAP_STS_REG_READ_COUNT_MASK (7 << 5) +#define MCAP_STS_FIFO_OVERFLOW_MASK (1 << 8) +#define MCAP_STS_FIFO_OCCUPANCY_MASK (15 << 12) +#define MCAP_STS_CFG_MCAP_REQ_MASK (1 << 24) + +/* Maximum FIFO Depth */ +#define MCAP_FIFO_DEPTH 16 + +/* PCIe Extended Capability Id */ +#define MCAP_EXT_CAP_ID 0xB + +/* Error Values */ +#define EMCAPREQ 120 +#define EMCAPRESET 121 +#define EMCAPMODRESET 122 +#define EMCAPFULLRESET 123 +#define EMCAPWRITE 124 +#define EMCAPREAD 125 +#define EMCAPCFG 126 +#define EMCAPBUSWALK 127 +#define EMCAPCFGACC 128 + +#undef DEBUG + +#ifndef DEBUG +#define pr_dbg(fmt, ...) do {} while (0) +#else +#define pr_dbg printf +#endif + +#define pr_info printf +#define pr_err printf + +/* MCAP Device Information */ +struct mcap_dev { + struct pci_dev *pdev; + struct pci_access *pacc; + unsigned int reg_base; +}; + +#define MCapRegWrite(mdev, offset, value) \ + pci_write_long(mdev->pdev, mdev->reg_base + offset, value) + +#define MCapRegRead(mdev, offset) \ + pci_read_long(mdev->pdev, mdev->reg_base + offset) + +#define IsResetSet(mdev) \ + (MCapRegRead(mdev, MCAP_CONTROL) & \ + MCAP_CTRL_RESET_MASK ? 1 : 0) + +#define IsModuleResetSet(mdev) \ + (MCapRegRead(mdev, MCAP_CONTROL) & \ + MCAP_CTRL_MOD_RESET_MASK ? 1 : 0) + +#define IsConfigureMCapReqSet(mdev) \ + (MCapRegRead(mdev, MCAP_STATUS) & \ + MCAP_STS_CFG_MCAP_REQ_MASK ? 1 : 0) + +#define IsErrSet(mdev) \ + (MCapRegRead(mdev, MCAP_STATUS) & \ + MCAP_STS_ERR_MASK ? 1 : 0) + +#define IsRegReadComplete(mdev) \ + (MCapRegRead(mdev, MCAP_STATUS) & \ + MCAP_STS_REG_READ_CMP_MASK ? 1 : 0) + +#define IsFifoOverflow(mdev) \ + (MCapRegRead(mdev, MCAP_STATUS) & \ + MCAP_STS_FIFO_OVERFLOW_MASK ? 1 : 0) + +#define GetRegReadCount(mdev) \ + ((MCapRegRead(mdev, MCAP_STATUS) & \ + MCAP_STS_REG_READ_COUNT_MASK) >> 5) + +/* Function Prototypes */ +struct mcap_dev *MCapLibInit(int device_id); +void MCapLibFree(struct mcap_dev *mdev); +void MCapDumpRegs(struct mcap_dev *mdev); +void MCapDumpReadRegs(struct mcap_dev *mdev); +int MCapReset(struct mcap_dev *mdev); +int MCapModuleReset(struct mcap_dev *mdev); +int MCapFullReset(struct mcap_dev *mdev); +int MCapShowDevice(struct mcap_dev *mdev, int verbose); +int MCapConfigureFPGA(struct mcap_dev *mdev, char *file_path); +int MCapReadRegisters(struct mcap_dev *mdev, u32 *data); +int MCapAccessConfigSpace(struct mcap_dev *mdev, int argc, char **argv);