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 <sthokal@xilinx.com> Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com>
This commit is contained in:
parent
e3b8e045d0
commit
e29e5689e0
6 changed files with 1045 additions and 12 deletions
30
README.txt
30
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
|
||||
|
|
35
mcap/linux/Makefile
Normal file
35
mcap/linux/Makefile
Normal file
|
@ -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
|
56
mcap/linux/README
Normal file
56
mcap/linux/README
Normal file
|
@ -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=<PATH to PCI Utilities Source>
|
||||
|
||||
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 <file> 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 <address> [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
|
167
mcap/linux/mcap.c
Normal file
167
mcap/linux/mcap.c
Normal file
|
@ -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 <file>\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 <address> [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;
|
||||
}
|
611
mcap/linux/mcap_lib.c
Normal file
611
mcap/linux/mcap_lib.c
Normal file
|
@ -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);
|
||||
}
|
158
mcap/linux/mcap_lib.h
Normal file
158
mcap/linux/mcap_lib.h
Normal file
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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);
|
Loading…
Add table
Reference in a new issue