📄 bfload.c
字号:
/*************************************************************************** bfload - loads xilinx bitfile into mesa 5i20 board FPGA** Copyright (C) 2007 John Kasunich (jmkasunich at fastmail dot fm)* portions based on m5i20cfg by Peter C. Wallace***************************************************************************This program is free software; you can redistribute it and/ormodify it under the terms of version 2 of the GNU GeneralPublic License as published by the Free Software Foundation.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USATHE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FORANY HARM OR LOSS RESULTING FROM ITS USE. IT IS _EXTREMELY_ UNWISETO RELY ON SOFTWARE ALONE FOR SAFETY. Any machinery capable ofharming persons must have provisions for completely removing powerfrom all motors, etc, before persons enter any danger area. Allmachinery must be designed to comply with local and national safetycodes, and the authors of this software can not, and do not, takeany responsibility for such compliance.This code was written as part of the EMC HAL project. For moreinformation, go to www.linuxcnc.org.**************************************************************************Info about programming the 5i20:Board wiring (related to programming): unused <-- 9030 pin 156, GPIO2, bit 8 reg 0x54 FPGA pin 104 = DONE --> 9030 pin 157, GPIO3, bit 11 reg 0x54 FGPA pin 107 = /INIT --> 9030 pin 137, GPIO4, bit 14 reg 0x54 STATUS LED CR11 (low = on) <-- 9030 pin 136, GPIO5, bit 17 reg 0x54 unused <-- 9030 pin 135, GPIO6, bit 20 reg 0x54 FPGA pin 161 = /WRITE <-- 9030 pin 134, GPIO7, but 23 reg 0x54 FPGA pin 106 = /PROGRAM, <-- 9030 pin 94, GPIO8, bit 26 reg 0x54 FPGA pin 155 = CCLK <-> FPGA pin 182 (LCLK 33MHz) FPGA pin 160 = /CS <-- /LWR (local bus write strobe) FPGA pin 153 = D0 <-> LAD0 (local data bus) FPGA pin 146 = D1 <-> LAD1 (local data bus) FPGA pin 142 = D2 <-> LAD2 (local data bus) FPGA pin 135 = D3 <-> LAD3 (local data bus) FPGA pin 126 = D4 <-> LAD4 (local data bus) FPGA pin 119 = D5 <-> LAD5 (local data bus) FPGA pin 115 = D6 <-> LAD6 (local data bus) FPGA pin 108 = D7 <-> LAD7 (local data bus)Programming sequence: set /PROGRAM low for 300nS minimum (resets chip and starts clearing memory) /INIT and DONE go low set /PROGRAM high wait for /INIT to go high (100uS max, when done clearing memory) set /WRITE low send data bytes (each byte strobes /CS low) the last few bytes in the file are dummies, which provide the clocks needed to let the device come out of config mode and begin running if a CRC error is detected, /INIT will go low DONE will go high during the dummy bytes at the end of the file set /WRITE high**************************************************************************Info about programming the 5i22:Board wiring (related to programming): FPGA pin R15 = DONE --> 9054 pin 159, USERI/ FGPA pin U10 = /INIT --> not accessible from the PC FPGA pin V3 = RD_WR/ <-- pulled low? FPGA pin E5 = /PROGRAM, <-- 9054 pin 154, USERO/ FPGA pin T15 = CCLK <-> FPGA pin ??? (LCLK 33MHz???) FPGA pin V2 = /CS <-- /LWR (local bus write strobe) FPGA pin T12 = D0 <-> LAD0 (local data bus) FPGA pin R12 = D1 <-> LAD1 (local data bus) FPGA pin N11 = D2 <-> LAD2 (local data bus) FPGA pin P11 = D3 <-> LAD3 (local data bus) FPGA pin U9 = D4 <-> LAD4 (local data bus) FPGA pin V9 = D5 <-> LAD5 (local data bus) FPGA pin R7 = D6 <-> LAD6 (local data bus) FPGA pin T7 = D7 <-> LAD7 (local data bus)Programming sequence: set /PROGRAM low for 300nS minimum (resets chip and starts clearing memory) /INIT and DONE go low (verify that DONE is low, /INIT is inaccessible) set /PROGRAM high wait at least 100uS for clearing memory (INIT/ goes high but can't sense it) set /WRITE low (maybe already pulled low?) send data bytes (each byte strobes /CS low) the last few bytes in the file are dummies, which provide the clocks needed to let the device come out of config mode and begin running if a CRC error is detected, /INIT will go low (can't tell) and DONE will not go high. DONE will go high during the dummy bytes at the end of the file if all is OK set /WRITE high (or maybe leave alone)*************************************************************************///#define _GNU_SOURCE /* getline() */#include <errno.h>#include <stdarg.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/io.h>#include <sys/stat.h>#include <sys/types.h>#include <linux/types.h>#include "epp.h"#include "upci.h"#include "bitfile.h"/************************************************************************/#define MASK(x) (1<<(x)) /* gets a bit in position (x) */#define CHECK_W(w,x) ((w&MASK(x))==MASK(x)) /* true if bit x in w is set *//* I/O registers */#define CTRL_STAT_OFFSET 0x0054 /* 9030 GPIO register (region 1) *///// the LAS?BRD registers are in the PLX 9030// HostMot2 firmware needs the #READY bit (0x2) set in order to work, but// some older eeproms on the 5i20 (and maybe other cards) dont set them// right, but we can detect the problem and fix it up//#define LAS0BRD_OFFSET 0x28#define LAS1BRD_OFFSET 0x2C#define LAS2BRD_OFFSET 0x30#define LAS3BRD_OFFSET 0x34#define LASxBRD_READY 0x2 /* bit number in 9030 GPIO register */#define GPIO_3_MASK (1<<11) /* GPIO 3 */#define DONE_MASK (1<<11) /* GPIO 3 */#define _INIT_MASK (1<<14) /* GPIO 4 */#define _LED_MASK (1<<17) /* GPIO 5 */#define GPIO_6_MASK (1<<20) /* GPIO 6 */#define _WRITE_MASK (1<<23) /* GPIO 7 */#define _PROGRAM_MASK (1<<26) /* GPIO 8 *//* Exit codes */#define EC_OK 0 /* Exit OK. */#define EC_BADCL 100 /* Bad command line. */#define EC_HDW 101 /* Some sort of hardware failure on the 5I20. */#define EC_FILE 102 /* File error of some sort. */#define EC_SYS 103 /* Beyond our scope. *//* I/O register indices.*/#define CTRL_STAT_OFFSET_5I22 0x006C /* 5I22 32-bit control/status register. */ /* bit number in 9054 GPIO register */ /* yes, the direction control bits are not in the same order as the I/O bits */#define DONE_MASK_5I22 (1<<17) /* GPI */#define _PROGRAM_MASK_5I22 (1<<16) /* GPO, active low */#define DONE_ENABLE_5I22 (1<<18) /* GPI direction control, 1=input */#define _PROG_ENABLE_5I22 (1<<19) /* GPO direction control, 1=output *//* how long should we wait for DONE when programming 9054-based cards */#define DONE_WAIT_5I22 20000/************************************************************************///// this data structure describes a board we know how to program//struct board_info { char *board_type; char *chip_type; enum { IO_TYPE_PCI, IO_TYPE_EPP } io_type; union { struct { unsigned short vendor_id; unsigned short device_id; unsigned short ss_vendor_id; unsigned short ss_device_id; int fpga_pci_region; int upci_devnum; } pci; struct epp epp; } io; int (*program_funct) (struct board_info *bd, struct bitfile_chunk *ch);};//// these are the functions that actually program the FPGA//static int program_5i20_fpga(struct board_info *bd, struct bitfile_chunk *ch);static int program_5i22_fpga(struct board_info *bd, struct bitfile_chunk *ch);static int program_7i43_fpga(struct board_info *board, struct bitfile_chunk *ch);// // this array describes all the boards we know how to program//struct board_info board_info_table[] = { { .board_type = "5i20", .chip_type = "2s200pq208", .io_type = IO_TYPE_PCI, .io.pci.vendor_id = 0x10B5, .io.pci.device_id = 0x9030, .io.pci.ss_vendor_id = 0x10B5, .io.pci.ss_device_id = 0x3131, .io.pci.fpga_pci_region = 5, .io.pci.upci_devnum = 0, .program_funct = program_5i20_fpga }, { .board_type = "5i22-1M", .chip_type = "3s1000fg320", .io_type = IO_TYPE_PCI, .io.pci.vendor_id = 0x10B5, .io.pci.device_id = 0x9054, .io.pci.ss_vendor_id = 0x10B5, .io.pci.ss_device_id = 0x3132, .io.pci.fpga_pci_region = 3, .io.pci.upci_devnum = 0, .program_funct = program_5i22_fpga }, { .board_type = "5i22-1.5M", .chip_type = "3s1500fg320", .io_type = IO_TYPE_PCI, .io.pci.vendor_id = 0x10B5, .io.pci.device_id = 0x9054, .io.pci.ss_vendor_id = 0x10B5, .io.pci.ss_device_id = 0x3131, .io.pci.fpga_pci_region = 3, .io.pci.upci_devnum = 0, .program_funct = program_5i22_fpga }, { .board_type = "7i43", .chip_type = "3s200tq144", .io_type = IO_TYPE_EPP, .io.epp.io_addr = 0x378, .io.epp.io_addr_hi = 0x778, .program_funct = program_7i43_fpga }, { .board_type = "7i43", .chip_type = "3s400tq144", .io_type = IO_TYPE_EPP, .io.epp.io_addr = 0x378, .io.epp.io_addr_hi = 0x778, .program_funct = program_7i43_fpga }};static void errmsg(const char *funct, const char *fmt, ...);static int parse_cmdline(unsigned argc, char *argv[]);static __u8 bit_reverse (__u8 data);static int write_fpga_ram(struct board_info *bd, struct bitfile_chunk *ch);/* globals to pass data from command line parser to main */static char *config_file_name;static int card_number;struct bitfile *open_bitfile_or_die(char *filename) { struct bitfile *bf; int r; printf ( "Reading '%s'...\n", filename); bf = bitfile_read(filename); if (bf == NULL) { errmsg(__func__, "reading bitstream file '%s'", filename ); exit(EC_FILE); } r = bitfile_validate_xilinx_info(bf); if (r != 0) { errmsg(__func__, "not a valid Xilinx bitfile"); exit(EC_FILE); } bitfile_print_xilinx_info(bf); return bf;}/***********************************************************************/int main(int argc, char *argv[]){ struct upci_dev_info info; int tablesize, n, retval; struct bitfile *bf; struct bitfile_chunk *ch; char *chip; struct board_info board; /* if we are setuid, drop privs until needed */ seteuid(getuid()); if ( parse_cmdline(argc, argv) != 0 ) { errmsg(__func__,"command line error" ); return EC_BADCL; } bf = open_bitfile_or_die(config_file_name); /* chunk 'b' has the target device */ ch = bitfile_find_chunk(bf, 'b', 0); chip = (char *)(ch->body); /* scan board specs table looking for a board that uses the chip for which this bitfile was targeted */ tablesize = sizeof(board_info_table) / sizeof(struct board_info); n = 0; while ( (board_info_table[n].io_type != IO_TYPE_PCI) || (strcmp(board_info_table[n].chip_type, chip ) != 0) ) { n++; if ( n >= tablesize ) { errmsg(__func__,"bitfile is targeted for a '%s' FPGA,\n" " but no supported board uses that device", ch->body ); return EC_FILE; } } /* copy board data from table to local struct */ board = board_info_table[n]; printf ( "Board type: %s\n", board.board_type ); /* chunk 'e' has the bitstream */ ch = bitfile_find_chunk(bf, 'e', 0); /* now deal with the hardware */ printf ( "Searching for board...\n" ); retval = upci_scan_bus(); if ( retval < 0 ) { errmsg(__func__,"PCI bus data missing" ); return EC_SYS; } info.vendor_id = board.io.pci.vendor_id; info.device_id = board.io.pci.device_id; info.ss_vendor_id = board.io.pci.ss_vendor_id; info.ss_device_id = board.io.pci.ss_device_id; info.instance = card_number; /* find the matching device */ board.io.pci.upci_devnum = upci_find_device(&info); if ( board.io.pci.upci_devnum < 0 ) { errmsg(__func__, "%s board #%d not found", board.board_type, info.instance ); return EC_HDW; } upci_print_device_info(board.io.pci.upci_devnum); printf ( "Loading configuration into %s board...\n", board.board_type ); retval = board.program_funct(&board, ch); if ( retval != 0 ) { errmsg(__func__, "configuration did not load"); return EC_HDW; } /* do we need to HAL driver data to the FGPA RAM? */ ch = bitfile_find_chunk(bf, 'r', 0); if ( ch != NULL ) { /* yes */ printf ( "Writing data to FPGA RAM\n" ); retval = write_fpga_ram(&board, ch); if ( retval != 0 ) { errmsg(__func__, "RAM data could not be loaded" ); return EC_HDW; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -