1344 lines
53 KiB
C
1344 lines
53 KiB
C
//
|
|
// Copyright (C) 2013-2014 Michael Geszkiewicz
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
//
|
|
|
|
#ifdef __linux__
|
|
#include <sys/mman.h>
|
|
#include <sys/io.h>
|
|
#include <pci/pci.h>
|
|
#include <sys/time.h>
|
|
#elif _WIN32
|
|
#include <windows.h>
|
|
#include "libpci/pci.h"
|
|
#endif
|
|
#include <assert.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include "types.h"
|
|
#include "common.h"
|
|
#include "eeprom.h"
|
|
#include "eeprom_local.h"
|
|
#include "bitfile.h"
|
|
#include "pci_boards.h"
|
|
|
|
extern board_t boards[MAX_BOARDS];
|
|
extern int boards_count;
|
|
static int memfd = -1;
|
|
struct pci_access *pacc;
|
|
static u8 file_buffer[SECTOR_SIZE];
|
|
|
|
static int pci_read(llio_t *self, u32 addr, void *buffer, int size);
|
|
static int pci_write(llio_t *self, u32 addr, void *buffer, int size);
|
|
|
|
u16 setup_eeprom_5i20[256] = {
|
|
0x9030, // DEVICE ID
|
|
0x10B5, // VENDOR ID
|
|
0x0290, // PCI STATUS
|
|
0x0000, // PCI COMMAND
|
|
0x1180, // CLASS CODE (Changed to Data Acq to fool some BIOSs)
|
|
0x0000, // CLASS CODE / REV
|
|
0x3131, // SUBSYSTEM ID
|
|
0x10B5, // SUBSYSTEM VENDOR ID
|
|
|
|
0x0000, // MSB NEW CAPABILITY POINTER
|
|
0x0040, // LSB NEW CAPABILITY POINTER
|
|
0x0000, // RESERVED
|
|
0x0100, // INTERRUPT PIN
|
|
0x0000, // MSW OF POWER MANAGEMENT CAPABILITIES
|
|
0x0000, // LSW OF POWER MANAGEMANT CAPABILITIES
|
|
0x0000, // MSW OF POWER MANAGEMENT DATA / PMCSR BRIDGE SUPPORT EXTENSION
|
|
0x0000, // LSW OF POWER MANAGEMENT CONTROL STATUS
|
|
|
|
0x0000, // MSW OF HOT SWAP CONTROL / STATUS
|
|
0x0000, // LSW OF HOTSWAP NEXT CAPABILITY POINTER / HOT SWAP CONTROL
|
|
0x0000, // PCI VITAL PRODUCT DATA ADDRESS
|
|
0x0000, // PCI VITAL PRODUCT NEXT CAPABILITY POINTER / PCI VITAL PRODUCT DATA CONTROL
|
|
0x0FFF, // MSW OF LOCAL ADDRESS SPACE 0 RANGE
|
|
0xFF01, // LSW OF LOCAL ADDRESS SPACE 0 RANGE
|
|
0x0FFF, // MSW OF LOCAL ADDRESS SPACE 1 RANGE
|
|
0xFF01, // LSW OF LOCAL ADDRESS SPACE 1 RANGE
|
|
|
|
0x0FFF, // MSW OF LOCAL ADDRESS SPACE 2 RANGE
|
|
0x0000, // LSW OF LOCAL ADDRESS SPACE 2 RANGE
|
|
0x0FFF, // MSW OF LOCAL ADDRESS SPACE 3 RANGE
|
|
0x0000, // LSW OF LOCAL ADDRESS SPACE 3 RANGE
|
|
0x0000, // MSW OF EXPANSION ROM RANGE
|
|
0x0000, // LSW OF EXPANSION ROM RANGE
|
|
0x0000, // MSW OF LOCAL ADDRESS SPACE 0 LOCAL BASE ADDRESS (REMAP)
|
|
0x0001, // LSW OF LOCAL ADDRESS SPACE 0 LOCAL BASE ADDRESS (REMAP)
|
|
|
|
0x0000, // MSW OF LOCAL ADDRESS SPACE 1 LOCAL BASE ADDRESS (REMAP)
|
|
0x0001, // LSW OF LOCAL ADDRESS SPACE 1 LOCAL BASE ADDRESS (REMAP)
|
|
0x0000, // MSW OF LOCAL ADDRESS SPACE 2 LOCAL BASE ADDRESS (REMAP)
|
|
0x0001, // LSW OF LOCAL ADDRESS SPACE 2 LOCAL BASE ADDRESS (REMAP)
|
|
0x0000, // MSW OF LOCAL ADDRESS SPACE 3 LOCAL BASE ADDRESS (REMAP)
|
|
0x0001, // LSW OF LOCAL ADDRESS SPACE 3 LOCAL BASE ADDRESS (REMAP)
|
|
0x0000, // MSW OF EXPANSION ROM LOCAL BASE ADDRESS (REMAP)
|
|
0x0000, // LSW OF EXPANSION ROM LOCAL BASE ADDRESS (REMAP)
|
|
|
|
0x0040, // MSW OF LOCAL ADDRESS SPACE 0 BUS DESCRIPTOR
|
|
0x0002, // LSW OF LOCAL ADDRESS SPACE 0 BUS DESCRIPTOR
|
|
0x0080, // MSW OF LOCAL ADDRESS SPACE 1 BUS DESCRIPTOR
|
|
0x0002, // LSW OF LOCAL ADDRESS SPACE 1 BUS DESCRIPTOR
|
|
0x0040, // MSW OF LOCAL ADDRESS SPACE 2 BUS DESCRIPTOR
|
|
0x0002, // LSW OF LOCAL ADDRESS SPACE 2 BUS DESCRIPTOR
|
|
0x0080, // MSW OF LOCAL ADDRESS SPACE 3 BUS DESCRIPTOR
|
|
0x0002, // LSW OF LOCAL ADDRESS SPACE 3 BUS DESCRIPTOR
|
|
|
|
0x0000, // MSW OF EXPANSION ROM BUS DESCRIPTOR
|
|
0x0002, // LSW OF EXPANSION ROM BUS DESCRIPTOR
|
|
0x0000, // MSW OF CHIP SELECT 0 BASE ADDRESS
|
|
0x0000, // LSW OF CHIP SELECT 0 BASE ADDRESS
|
|
0x0000, // MSW OF CHIP SELECT 1 BASE ADDRESS
|
|
0x0000, // LSW OF CHIP SELECT 1 BASE ADDRESS
|
|
0x0000, // MSW OF CHIP SELECT 2 BASE ADDRESS
|
|
0x0000, // LSW OF CHIP SELECT 2 BASE ADDRESS
|
|
|
|
0x0000, // MSW OF CHIP SELECT 3 BASE ADDRESS
|
|
0x0000, // LSW OF CHIP SELECT 3 BASE ADDRESS
|
|
0x0000, // SERIAL EEPROM WRITE PROTECTED ADDRESS BOUNDARY
|
|
0x0041, // LSW OF INTERRUPT CONTROL / STATUS
|
|
0x0878, // MSW OF PCI TARGET RESPONSE, SERIAL EEPROM, AND INITIALIZATION CONTROL
|
|
0x0000, // LSW OF PCI TARGET RESPONSE, SERIAL EEPROM, AND INITIALIZATION CONTROL
|
|
0x024B, // MSW OF GENERAL PURPOSE I/O CONTROL
|
|
0x009B, // LSW OF GENERAL PURPOSE I/O CONTROL
|
|
};
|
|
|
|
u16 setup_eeprom_3x20_10[256] = {
|
|
0x9056, // DEVICE ID PCIIDR[31:16]
|
|
0x10B5, // VENDOR ID PCIIDR[15:0]
|
|
0x0680, // CLASS CODE PCICCR[23:8]
|
|
0x0000, // CLASS CODE/REVISION PCICCR[7:0]/PCIREV[7:0]
|
|
0x0000, // MAXIMUM LATENCY/MINIMUM GRANT PCIMLR[7:0]/PCIMGR[7:0]
|
|
0x0100, // INTERRUPT PIN/INTERRUPT PIN ROUTING PCIIPR[7:0]/PCIIL[7:0]
|
|
0x0000, // MSW OF MAILBOX0 MBOX0[31:16]
|
|
0x0000, // LSW OF MAILBOX0 MBOX0[15:0]
|
|
|
|
0x0000, // MSW OF MAILBOX1 MBOX1[31:16]
|
|
0x0000, // LSW OF MAILBOX1 MBOX1[15:0]
|
|
0xFFFF, // MSW OF PCI-LOCAL RANGE0 LAS0RR[31:16]
|
|
0xFF01, // LSW OF PCI-LOCAL RANGE0 LAS0RR[15:0]
|
|
0x0000, // MSW OF PCI-LOCAL REMAP0 LAS0BA[31:16]
|
|
0x0001, // LSW OF PCI-LOCAL REMAP0 LAS0BA[15:0]
|
|
0x0200, // MSW OF DMA ARBITRATION REGISTER MARBR[31:16]
|
|
0x0000, // LSW OF DMA ARBITRATION REGISTER MARBR[15:0]
|
|
|
|
0x0030, // MSW OF SERIAL EEPROM WP ADDRESS PROT_AREA[15:0]
|
|
0x0500, // LSW OF MISC CONT REG/LSW OF BIG/LITTLE REG LMISC[7:0]/BIGEND[7:0]
|
|
0xFFFF, // MSW OF PCI EXPANSION ROM RANGE EROMRR[31:16]
|
|
0x0000, // LSW OF PCI EXPANSION ROM RANGE EROMRR[15:0]
|
|
0x0000, // MSW OF PCI EXPANSION ROM REMAP EROMBA[31:16]
|
|
0x0000, // LSW OF PCI EXPANSION ROM REMAP EROMBA[15:0]
|
|
0x4243, // MSW OF BUS DESCRIPTORS FOR LOCAL SPACE 0 LBRD0[31:16]
|
|
0x0043, // LSW OF BUS DESCRIPTORS FOR LOCAL SPACE 0 LBRD0[15:0]
|
|
|
|
0x0000, // MSW OF PCI INITIATOR - PCI RANGE DMRR[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR - PCI RANGE DMRR[15:0]
|
|
0x0000, // MSW OF PCI INITIATOR - PCI LOCAL BASE ADD DMLBAM[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR - PCI LOCAL BASE ADD DMLBAM[15:0]
|
|
0x0000, // MSW OF PCI INITIATOR - PCI LBA I/O CONF DMLBA[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR - PCI LBA I/O CONF DMLBA[15:0]
|
|
0x0000, // MSW OF PCI INITIATOR - PCI BASE ADDRESS DMPBAM[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR - PCI BASE ADDRESS DMPBAM[15:0]
|
|
|
|
0x0000, // MSW OF PCI INITIATOR PCI CONF ADD DMCFGA[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR PCI CONF ADD DMCFGA[15:0]
|
|
0x3427, // SUBSYSTEM ID PCISID[15:0]
|
|
0x10B5, // SUBSYSTEM VENDOR ID PCISVID[15:0]
|
|
0xFFFF, // MSW OF PCI-LOCAL RANGE1 LAS1RR[31:16]
|
|
0x0000, // LSW OF PCI-LOCAL RANGE1 LAS1RR[15:0]
|
|
0x0000, // MSW OF PCI-LOCAL REMAP1 LAS1BA[31:16]
|
|
0x0001, // LSW OF PCI-LOCAL REMAP1 LAS1BA[15:0]
|
|
|
|
0x0000, // MSW OF BUS DESCRIPTORS FOR LOCAL SPACE 1 LBRD1[31:16]
|
|
0x0043, // LSW OF BUS DESCRIPTORS FOR LOCAL SPACE 1 LBRD1[15:0]
|
|
0x0000, // MSW OF HOT-SWAP CONTROL RESERVED
|
|
0x4C06, // LSW OF HS NEXT-CAP POINTER/HS CONT HS_NEXT/HS_CNTL[7:0]
|
|
};
|
|
|
|
u16 setup_eeprom_3x20_15[256] = {
|
|
0x9056, // DEVICE ID PCIIDR[31:16]
|
|
0x10B5, // VENDOR ID PCIIDR[15:0]
|
|
0x0680, // CLASS CODE PCICCR[23:8]
|
|
0x0000, // CLASS CODE/REVISION PCICCR[7:0]/PCIREV[7:0]
|
|
0x0000, // MAXIMUM LATENCY/MINIMUM GRANT PCIMLR[7:0]/PCIMGR[7:0]
|
|
0x0100, // INTERRUPT PIN/INTERRUPT PIN ROUTING PCIIPR[7:0]/PCIIL[7:0]
|
|
0x0000, // MSW OF MAILBOX0 MBOX0[31:16]
|
|
0x0000, // LSW OF MAILBOX0 MBOX0[15:0]
|
|
|
|
0x0000, // MSW OF MAILBOX1 MBOX1[31:16]
|
|
0x0000, // LSW OF MAILBOX1 MBOX1[15:0]
|
|
0xFFFF, // MSW OF PCI-LOCAL RANGE0 LAS0RR[31:16]
|
|
0xFF01, // LSW OF PCI-LOCAL RANGE0 LAS0RR[15:0]
|
|
0x0000, // MSW OF PCI-LOCAL REMAP0 LAS0BA[31:16]
|
|
0x0001, // LSW OF PCI-LOCAL REMAP0 LAS0BA[15:0]
|
|
0x0200, // MSW OF DMA ARBITRATION REGISTER MARBR[31:16]
|
|
0x0000, // LSW OF DMA ARBITRATION REGISTER MARBR[15:0]
|
|
|
|
0x0030, // MSW OF SERIAL EEPROM WP ADDRESS PROT_AREA[15:0]
|
|
0x0500, // LSW OF MISC CONT REG/LSW OF BIG/LITTLE REG LMISC[7:0]/BIGEND[7:0]
|
|
0xFFFF, // MSW OF PCI EXPANSION ROM RANGE EROMRR[31:16]
|
|
0x0000, // LSW OF PCI EXPANSION ROM RANGE EROMRR[15:0]
|
|
0x0000, // MSW OF PCI EXPANSION ROM REMAP EROMBA[31:16]
|
|
0x0000, // LSW OF PCI EXPANSION ROM REMAP EROMBA[15:0]
|
|
0x4243, // MSW OF BUS DESCRIPTORS FOR LOCAL SPACE 0 LBRD0[31:16]
|
|
0x0043, // LSW OF BUS DESCRIPTORS FOR LOCAL SPACE 0 LBRD0[15:0]
|
|
|
|
0x0000, // MSW OF PCI INITIATOR - PCI RANGE DMRR[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR - PCI RANGE DMRR[15:0]
|
|
0x0000, // MSW OF PCI INITIATOR - PCI LOCAL BASE ADD DMLBAM[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR - PCI LOCAL BASE ADD DMLBAM[15:0]
|
|
0x0000, // MSW OF PCI INITIATOR - PCI LBA I/O CONF DMLBA[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR - PCI LBA I/O CONF DMLBA[15:0]
|
|
0x0000, // MSW OF PCI INITIATOR - PCI BASE ADDRESS DMPBAM[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR - PCI BASE ADDRESS DMPBAM[15:0]
|
|
|
|
0x0000, // MSW OF PCI INITIATOR PCI CONF ADD DMCFGA[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR PCI CONF ADD DMCFGA[15:0]
|
|
0x3428, // SUBSYSTEM ID PCISID[15:0]
|
|
0x10B5, // SUBSYSTEM VENDOR ID PCISVID[15:0]
|
|
0xFFFF, // MSW OF PCI-LOCAL RANGE1 LAS1RR[31:16]
|
|
0x0000, // LSW OF PCI-LOCAL RANGE1 LAS1RR[15:0]
|
|
0x0000, // MSW OF PCI-LOCAL REMAP1 LAS1BA[31:16]
|
|
0x0001, // LSW OF PCI-LOCAL REMAP1 LAS1BA[15:0]
|
|
|
|
0x0000, // MSW OF BUS DESCRIPTORS FOR LOCAL SPACE 1 LBRD1[31:16]
|
|
0x0043, // LSW OF BUS DESCRIPTORS FOR LOCAL SPACE 1 LBRD1[15:0]
|
|
0x0000, // MSW OF HOT-SWAP CONTROL RESERVED
|
|
0x4C06, // LSW OF HS NEXT-CAP POINTER/HS CONT HS_NEXT/HS_CNTL[7:0]
|
|
};
|
|
|
|
u16 setup_eeprom_3x20_20[256] = {
|
|
0x9056, // DEVICE ID PCIIDR[31:16]
|
|
0x10B5, // VENDOR ID PCIIDR[15:0]
|
|
0x0680, // CLASS CODE PCICCR[23:8]
|
|
0x0000, // CLASS CODE/REVISION PCICCR[7:0]/PCIREV[7:0]
|
|
0x0000, // MAXIMUM LATENCY/MINIMUM GRANT PCIMLR[7:0]/PCIMGR[7:0]
|
|
0x0100, // INTERRUPT PIN/INTERRUPT PIN ROUTING PCIIPR[7:0]/PCIIL[7:0]
|
|
0x0000, // MSW OF MAILBOX0 MBOX0[31:16]
|
|
0x0000, // LSW OF MAILBOX0 MBOX0[15:0]
|
|
|
|
0x0000, // MSW OF MAILBOX1 MBOX1[31:16]
|
|
0x0000, // LSW OF MAILBOX1 MBOX1[15:0]
|
|
0xFFFF, // MSW OF PCI-LOCAL RANGE0 LAS0RR[31:16]
|
|
0xFF01, // LSW OF PCI-LOCAL RANGE0 LAS0RR[15:0]
|
|
0x0000, // MSW OF PCI-LOCAL REMAP0 LAS0BA[31:16]
|
|
0x0001, // LSW OF PCI-LOCAL REMAP0 LAS0BA[15:0]
|
|
0x0200, // MSW OF DMA ARBITRATION REGISTER MARBR[31:16]
|
|
0x0000, // LSW OF DMA ARBITRATION REGISTER MARBR[15:0]
|
|
|
|
0x0030, // MSW OF SERIAL EEPROM WP ADDRESS PROT_AREA[15:0]
|
|
0x0500, // LSW OF MISC CONT REG/LSW OF BIG/LITTLE REG LMISC[7:0]/BIGEND[7:0]
|
|
0xFFFF, // MSW OF PCI EXPANSION ROM RANGE EROMRR[31:16]
|
|
0x0000, // LSW OF PCI EXPANSION ROM RANGE EROMRR[15:0]
|
|
0x0000, // MSW OF PCI EXPANSION ROM REMAP EROMBA[31:16]
|
|
0x0000, // LSW OF PCI EXPANSION ROM REMAP EROMBA[15:0]
|
|
0x4243, // MSW OF BUS DESCRIPTORS FOR LOCAL SPACE 0 LBRD0[31:16]
|
|
0x0043, // LSW OF BUS DESCRIPTORS FOR LOCAL SPACE 0 LBRD0[15:0]
|
|
|
|
0x0000, // MSW OF PCI INITIATOR - PCI RANGE DMRR[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR - PCI RANGE DMRR[15:0]
|
|
0x0000, // MSW OF PCI INITIATOR - PCI LOCAL BASE ADD DMLBAM[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR - PCI LOCAL BASE ADD DMLBAM[15:0]
|
|
0x0000, // MSW OF PCI INITIATOR - PCI LBA I/O CONF DMLBA[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR - PCI LBA I/O CONF DMLBA[15:0]
|
|
0x0000, // MSW OF PCI INITIATOR - PCI BASE ADDRESS DMPBAM[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR - PCI BASE ADDRESS DMPBAM[15:0]
|
|
|
|
0x0000, // MSW OF PCI INITIATOR PCI CONF ADD DMCFGA[31:16]
|
|
0x0000, // LSW OF PCI INITIATOR PCI CONF ADD DMCFGA[15:0]
|
|
0x3429, // SUBSYSTEM ID PCISID[15:0]
|
|
0x10B5, // SUBSYSTEM VENDOR ID PCISVID[15:0]
|
|
0xFFFF, // MSW OF PCI-LOCAL RANGE1 LAS1RR[31:16]
|
|
0x0000, // LSW OF PCI-LOCAL RANGE1 LAS1RR[15:0]
|
|
0x0000, // MSW OF PCI-LOCAL REMAP1 LAS1BA[31:16]
|
|
0x0001, // LSW OF PCI-LOCAL REMAP1 LAS1BA[15:0]
|
|
|
|
0x0000, // MSW OF BUS DESCRIPTORS FOR LOCAL SPACE 1 LBRD1[31:16]
|
|
0x0043, // LSW OF BUS DESCRIPTORS FOR LOCAL SPACE 1 LBRD1[15:0]
|
|
0x0000, // MSW OF HOT-SWAP CONTROL RESERVED
|
|
0x4C06, // LSW OF HS NEXT-CAP POINTER/HS CONT HS_NEXT/HS_CNTL[7:0]
|
|
};
|
|
|
|
static void plx9030_SetCSHigh(board_t *board) {
|
|
u16 data = inw(board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
|
|
data = data | PLX9030_EECS_MASK;
|
|
outw(data, board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
sleep_ns(4000);
|
|
}
|
|
|
|
static void plx9030_SetCSLow(board_t *board) {
|
|
u16 data = inw(board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
|
|
data = data & (~PLX9030_EECS_MASK);
|
|
outw(data, board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
sleep_ns(4000);
|
|
}
|
|
|
|
static void plx9030_SetDinHigh(board_t *board) {
|
|
u16 data = inw(board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
|
|
data = data | PLX9030_EEDI_MASK;
|
|
outw(data, board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
sleep_ns(4000);
|
|
}
|
|
|
|
static void plx9030_SetDinLow(board_t *board) {
|
|
u16 data = inw(board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
|
|
data = data & (~PLX9030_EEDI_MASK);
|
|
outw(data, board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
sleep_ns(4000);
|
|
}
|
|
|
|
static void plx9030_SetClockHigh(board_t *board) {
|
|
u16 data = inw(board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
|
|
data = data | PLX9030_EECLK_MASK;
|
|
outw(data, board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
sleep_ns(4000);
|
|
}
|
|
|
|
static void plx9030_SetClockLow(board_t *board) {
|
|
u16 data = inw(board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
|
|
data = data & (~PLX9030_EECLK_MASK);
|
|
outw(data, board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
sleep_ns(4000);
|
|
}
|
|
|
|
static int plx9030_DataHighQ(board_t *board) {
|
|
u16 data = inw(board->ctrl_base_addr + PLX9030_CTRL_INIT_OFFSET);
|
|
|
|
sleep_ns(4000);
|
|
if ((data & PLX9030_EEDO_MASK) != 0)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static u16 plx9030_read_eeprom_word(board_t *board, u8 reg) {
|
|
u8 bit;
|
|
u16 mask;
|
|
u16 tdata;
|
|
|
|
plx9030_SetCSLow(board);
|
|
plx9030_SetDinLow(board);
|
|
plx9030_SetClockLow(board);
|
|
plx9030_SetCSHigh(board);
|
|
// send command first
|
|
mask = EEPROM_93C66_CMD_MASK;
|
|
for (bit = 0; bit < EEPROM_93C66_CMD_LEN; bit++) {
|
|
if ((mask & EEPROM_93C66_CMD_READ) == 0)
|
|
plx9030_SetDinLow(board);
|
|
else
|
|
plx9030_SetDinHigh(board);
|
|
mask = mask >> 1;
|
|
plx9030_SetClockLow(board);
|
|
plx9030_SetClockHigh(board);
|
|
}
|
|
// then send address
|
|
mask = EEPROM_93C66_ADDR_MASK;
|
|
for (bit = 0; bit < EEPROM_93C66_ADDR_LEN; bit++) {
|
|
if ((mask & reg) == 0)
|
|
plx9030_SetDinLow(board);
|
|
else
|
|
plx9030_SetDinHigh(board);
|
|
mask = mask >> 1;
|
|
plx9030_SetClockLow(board);
|
|
plx9030_SetClockHigh(board);
|
|
}
|
|
// read dummy 0 bit, if zero assume ok
|
|
if (plx9030_DataHighQ(board) == 1)
|
|
return 0;
|
|
mask = EEPROM_93C66_DATA_MASK;
|
|
tdata = 0;
|
|
for (bit = 0; bit < EEPROM_93C66_DATA_LEN; bit++) {
|
|
plx9030_SetClockLow(board);
|
|
plx9030_SetClockHigh(board);
|
|
if (plx9030_DataHighQ(board) == 1)
|
|
tdata = tdata | mask;
|
|
mask = mask >> 1;
|
|
}
|
|
plx9030_SetCSLow(board);
|
|
plx9030_SetDinLow(board);
|
|
plx9030_SetClockLow(board);
|
|
return tdata;
|
|
}
|
|
|
|
static void pci_plx9030_bridge_eeprom_setup_read(board_t *board) {
|
|
int i;
|
|
char *bridge_name = "Unknown";
|
|
|
|
if (board->dev->device_id == DEVICEID_PLX9030)
|
|
bridge_name = "PLX9030";
|
|
else if (board->dev->device_id == DEVICEID_PLX9054)
|
|
bridge_name = "PLX9054";
|
|
else if (board->dev->device_id == DEVICEID_PLX9056)
|
|
bridge_name = "PLX9056";
|
|
|
|
printf("%s PCI bridge setup EEPROM:\n", bridge_name);
|
|
for (i = 0; i < EEPROM_93C66_SIZE; i++) {
|
|
if ((i > 0) && ((i % 16) == 0))
|
|
printf("\n");
|
|
if ((i % 16) == 0)
|
|
printf(" %02X: ", i);
|
|
printf("%04X ", plx9030_read_eeprom_word(board, i));
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
static int plx9030_program_fpga(llio_t *self, char *bitfile_name) {
|
|
board_t *board = self->board;
|
|
int bindex, bytesread;
|
|
u32 status, control;
|
|
char part_name[32];
|
|
char board_name[32];
|
|
struct stat file_stat;
|
|
FILE *fp;
|
|
struct timeval tv1, tv2;
|
|
|
|
if (stat(bitfile_name, &file_stat) != 0) {
|
|
printf("Can't find file %s\n", bitfile_name);
|
|
return -1;
|
|
}
|
|
fp = fopen(bitfile_name, "rb");
|
|
if (fp == NULL) {
|
|
printf("Can't open file %s: %s\n", bitfile_name, strerror(errno));
|
|
return -1;
|
|
}
|
|
if (print_bitfile_header(fp, (char*) &part_name, (char*) &board_name, board->llio.verbose) == -1) {
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
if (!check_board_name(self->board_name, board_name, bitfile_name)) {
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
// set /WRITE low for data transfer, and turn on LED
|
|
status = inl(board->ctrl_base_addr + PLX9030_CTRL_STAT_OFFSET);
|
|
control = status & ~PLX9030_WRITE_MASK & ~PLX9030_LED_MASK;
|
|
outl(control, board->ctrl_base_addr + PLX9030_CTRL_STAT_OFFSET);
|
|
|
|
printf("Programming FPGA...\n");
|
|
printf(" |");
|
|
fflush(stdout);
|
|
gettimeofday(&tv1, NULL);
|
|
// program the FPGA
|
|
while (!feof(fp)) {
|
|
bytesread = fread(&file_buffer, 1, 8192, fp);
|
|
bindex = 0;
|
|
while (bindex < bytesread) {
|
|
outb(bitfile_reverse_bits(file_buffer[bindex]), board->data_base_addr);
|
|
bindex++;
|
|
}
|
|
printf("W");
|
|
fflush(stdout);
|
|
}
|
|
|
|
fclose(fp);
|
|
printf("\n");
|
|
if (board->llio.verbose == 1) {
|
|
gettimeofday(&tv2, NULL);
|
|
printf(" Programming time: %.2f seconds\n", (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
|
|
(double) (tv2.tv_sec - tv1.tv_sec));
|
|
}
|
|
|
|
// all bytes transferred, make sure FPGA is all set up now
|
|
status = inl(board->ctrl_base_addr + PLX9030_CTRL_STAT_OFFSET);
|
|
if (!(status & PLX9030_INIT_MASK)) {
|
|
// /INIT goes low on CRC error
|
|
printf("FPGA asserted /INIT: CRC error\n");
|
|
goto fail;
|
|
}
|
|
if (!(status & PLX9030_DONE_MASK)) {
|
|
printf("FPGA did not assert DONE\n");
|
|
goto fail;
|
|
}
|
|
|
|
// turn off write enable and LED
|
|
control = status | PLX9030_WRITE_MASK | PLX9030_LED_MASK;
|
|
outl(control, board->ctrl_base_addr + PLX9030_CTRL_STAT_OFFSET);
|
|
|
|
if (board->llio.verbose == 1) {
|
|
gettimeofday(&tv2, NULL);
|
|
printf("\n Programming time: %.3f seconds", (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
|
|
(double) (tv2.tv_sec - tv1.tv_sec));
|
|
}
|
|
printf("\nBoard FPGA programmed successfully.\n");
|
|
return 0;
|
|
|
|
fail:
|
|
// set /PROGRAM low (reset device), /WRITE high and LED off
|
|
status = inl(board->ctrl_base_addr + PLX9030_CTRL_STAT_OFFSET);
|
|
control = status & ~PLX9030_PROGRAM_MASK;
|
|
control |= PLX9030_WRITE_MASK | PLX9030_LED_MASK;
|
|
outl(control, board->ctrl_base_addr + PLX9030_CTRL_STAT_OFFSET);
|
|
return -EIO;
|
|
}
|
|
|
|
static int plx9030_reset(llio_t *self) {
|
|
board_t *board = self->board;
|
|
u32 status;
|
|
u32 control;
|
|
|
|
printf("Resetting FPGA... ");
|
|
status = inl(board->ctrl_base_addr + PLX9030_CTRL_STAT_OFFSET);
|
|
|
|
// set /PROGRAM bit low to reset the FPGA
|
|
control = status & ~PLX9030_PROGRAM_MASK;
|
|
|
|
// set /WRITE and /LED high (idle state)
|
|
control |= PLX9030_WRITE_MASK | PLX9030_LED_MASK;
|
|
|
|
// and write it back
|
|
outl(control, board->ctrl_base_addr + PLX9030_CTRL_STAT_OFFSET);
|
|
|
|
// verify that /INIT and DONE went low
|
|
status = inl(board->ctrl_base_addr + PLX9030_CTRL_STAT_OFFSET);
|
|
if (status & (PLX9030_DONE_MASK | PLX9030_INIT_MASK)) {
|
|
printf("FPGA did not reset: /INIT = %d, DONE = %d\n",
|
|
(status & PLX9030_INIT_MASK ? 1 : 0),
|
|
(status & PLX9030_DONE_MASK ? 1 : 0)
|
|
);
|
|
return -EIO;
|
|
}
|
|
|
|
// set /PROGRAM high, let FPGA come out of reset
|
|
control = status | PLX9030_PROGRAM_MASK;
|
|
outl(control, board->ctrl_base_addr + PLX9030_CTRL_STAT_OFFSET);
|
|
|
|
// wait for /INIT to go high when it finishes clearing memory
|
|
// This should take no more than 100uS. If we assume each PCI read
|
|
// takes 30nS (one PCI clock), that is 3300 reads. Reads actually
|
|
// take several clocks, but even at a microsecond each, 3.3mS is not
|
|
// an excessive timeout value
|
|
{
|
|
int count = 3300;
|
|
|
|
do {
|
|
status = inl(board->ctrl_base_addr + PLX9030_CTRL_STAT_OFFSET);
|
|
if (status & PLX9030_INIT_MASK) break;
|
|
} while (count-- > 0);
|
|
|
|
if (count == 0) {
|
|
printf("FPGA did not come out of /INIT\n");
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
printf("OK\n");
|
|
return 0;
|
|
}
|
|
|
|
static void plx9030_fixup_LASxBRD_READY(llio_t *self) {
|
|
board_t *board = self->board;
|
|
int offsets[] = {PLX9030_LAS0BRD_OFFSET, PLX9030_LAS1BRD_OFFSET, PLX9030_LAS2BRD_OFFSET, PLX9030_LAS3BRD_OFFSET};
|
|
int i;
|
|
|
|
for (i = 0; i < 4; i ++) {
|
|
u32 val;
|
|
int addr = board->ctrl_base_addr + offsets[i];
|
|
|
|
val = inl(addr);
|
|
if (!(val & PLX9030_LASxBRD_READY)) {
|
|
printf("LAS%dBRD #READY is off, enabling now\n", i);
|
|
val |= PLX9030_LASxBRD_READY;
|
|
outl(val, addr);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int plx905x_program_fpga(llio_t *self, char *bitfile_name) {
|
|
board_t *board = self->board;
|
|
int bindex, bytesread, i;
|
|
u32 status;
|
|
char part_name[32];
|
|
char board_name[32];
|
|
struct stat file_stat;
|
|
FILE *fp;
|
|
struct timeval tv1, tv2;
|
|
|
|
if (stat(bitfile_name, &file_stat) != 0) {
|
|
printf("Can't find file %s\n", bitfile_name);
|
|
return -1;
|
|
}
|
|
fp = fopen(bitfile_name, "rb");
|
|
if (fp == NULL) {
|
|
printf("Can't open file %s: %s\n", bitfile_name, strerror(errno));
|
|
return -1;
|
|
}
|
|
if (print_bitfile_header(fp, (char*) &part_name, (char*) &board_name, board->llio.verbose) == -1) {
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
if (!check_board_name(self->board_name, board_name, bitfile_name)) {
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
printf("Programming FPGA...\n");
|
|
printf(" |");
|
|
fflush(stdout);
|
|
gettimeofday(&tv1, NULL);
|
|
// program the FPGA
|
|
while (!feof(fp)) {
|
|
bytesread = fread(&file_buffer, 1, 8192, fp);
|
|
bindex = 0;
|
|
while (bindex < bytesread) {
|
|
outb(bitfile_reverse_bits(file_buffer[bindex]), board->data_base_addr);
|
|
bindex++;
|
|
}
|
|
printf("W");
|
|
fflush(stdout);
|
|
}
|
|
|
|
fclose(fp);
|
|
printf("\n");
|
|
if (board->llio.verbose == 1) {
|
|
gettimeofday(&tv2, NULL);
|
|
printf(" Programming time: %.2f seconds\n", (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
|
|
(double) (tv2.tv_sec - tv1.tv_sec));
|
|
}
|
|
|
|
// all bytes transferred, make sure FPGA is all set up now
|
|
for (i = 0; i < PLX905X_DONE_WAIT; i++) {
|
|
status = inl(board->ctrl_base_addr + PLX905X_CTRL_STAT_OFFSET);
|
|
if (status & PLX905X_DONE_MASK) break;
|
|
}
|
|
if (i >= PLX905X_DONE_WAIT) {
|
|
printf("Error: Not /DONE; programming not completed.\n");
|
|
return -EIO;
|
|
}
|
|
|
|
if (board->llio.verbose == 1) {
|
|
gettimeofday(&tv2, NULL);
|
|
printf("\n Programming time: %.3f seconds", (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
|
|
(double) (tv2.tv_sec - tv1.tv_sec));
|
|
}
|
|
printf("\nBoard FPGA programmed successfully.\n");
|
|
return 0;
|
|
}
|
|
|
|
static int plx905x_reset(llio_t *self) {
|
|
board_t *board = self->board;
|
|
int i;
|
|
u32 status, control;
|
|
|
|
printf("Resetting FPGA... ");
|
|
// set GPIO bits to GPIO function
|
|
status = inl(board->ctrl_base_addr + PLX905X_CTRL_STAT_OFFSET);
|
|
control = status | PLX905X_DONE_ENABLE | PLX905X_PROG_ENABLE;
|
|
outl(control, board->ctrl_base_addr + PLX905X_CTRL_STAT_OFFSET);
|
|
|
|
// Turn off /PROGRAM bit and insure that DONE isn't asserted
|
|
outl(control & ~PLX905X_PROGRAM_MASK, board->ctrl_base_addr + PLX905X_CTRL_STAT_OFFSET);
|
|
|
|
status = inl(board->ctrl_base_addr + PLX905X_CTRL_STAT_OFFSET);
|
|
if (status & PLX905X_DONE_MASK) {
|
|
// Note that if we see DONE at the start of programming, it's most
|
|
// likely due to an attempt to access the FPGA at the wrong I/O
|
|
// location.
|
|
printf("/DONE status bit indicates busy at start of programming\n");
|
|
return -EIO;
|
|
}
|
|
|
|
// turn on /PROGRAM output bit
|
|
outl(control | PLX905X_PROGRAM_MASK, board->ctrl_base_addr + PLX905X_CTRL_STAT_OFFSET);
|
|
|
|
// Delay for at least 100 uS. to allow the FPGA to finish its reset
|
|
// sequencing. 3300 reads is at least 100 us, could be as long as a
|
|
// few ms
|
|
for (i = 0; i < 3300; i++) {
|
|
status = inl(board->ctrl_base_addr + PLX905X_CTRL_STAT_OFFSET);
|
|
}
|
|
|
|
printf("OK\n");
|
|
return 0;
|
|
}
|
|
|
|
static void memcpy32(void *vdest, void *vsrc, int size) {
|
|
volatile u32 *dest = (volatile u32*)vdest;
|
|
volatile u32 *src = (volatile u32*)vsrc;
|
|
while(size) {
|
|
*dest = *src;
|
|
dest++;
|
|
src++;
|
|
size --;
|
|
}
|
|
}
|
|
|
|
static int pci_read(llio_t *self, u32 addr, void *buffer, int size) {
|
|
board_t *board = self->board;
|
|
assert(size % 4 == 0);
|
|
memcpy32(buffer, board->base + addr, size/4);
|
|
return 0;
|
|
}
|
|
|
|
static int pci_write(llio_t *self, u32 addr, void *buffer, int size) {
|
|
board_t *board = self->board;
|
|
assert(size % 4 == 0);
|
|
memcpy32(board->base + addr, buffer, size/4);
|
|
return 0;
|
|
}
|
|
|
|
static int pci_board_reload(llio_t *self, int fallback_flag) {
|
|
board_t *board = self->board;
|
|
int i;
|
|
u32 boot_addr, bar0_reg, cookie;
|
|
u16 cmd_reg;
|
|
|
|
pci_read(&(board->llio), HM2_ICAP_REG, &cookie, sizeof(u32));
|
|
if (cookie != HM2_ICAP_COOKIE) {
|
|
printf("ERROR: Active firmware too old to support --reload\n");
|
|
return -1;
|
|
}
|
|
|
|
if (fallback_flag == 1) {
|
|
boot_addr = 0x10000;
|
|
} else {
|
|
boot_addr = 0x0;
|
|
}
|
|
boot_addr |= 0x0B000000; // plus read command in high byte
|
|
|
|
u32 data[14] = {
|
|
0xFFFF, // dummy
|
|
0xFFFF, // dummy
|
|
0xAA99, // sync
|
|
0x5566, // sync
|
|
0x3261, // load low flash start address
|
|
boot_addr & 0xFFFF, // start addr
|
|
0x3281, // load high start address + read command
|
|
boot_addr >> 16, // start addr (plus read command in high byte)
|
|
0x30A1, // load command register
|
|
0x000E, // IPROG command
|
|
0x2000, // NOP
|
|
0x2000, // NOP
|
|
0x2000, // NOP
|
|
0x2000 // NOP
|
|
};
|
|
|
|
cmd_reg = pci_read_word(board->dev, PCI_COMMAND);
|
|
bar0_reg = pci_read_long(board->dev, PCI_BASE_ADDRESS_0);
|
|
for (i = 0; i < 14; i++) {
|
|
pci_write(&(board->llio), HM2_ICAP_REG, &data[i], sizeof(u32));
|
|
usleep(1000);
|
|
}
|
|
printf("Waiting for FPGA configuration...");
|
|
sleep(2);
|
|
printf("OK\n");
|
|
pci_write_word(board->dev, PCI_COMMAND, cmd_reg);
|
|
pci_write_long(board->dev, PCI_BASE_ADDRESS_0, bar0_reg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void pci_fix_bar_lengths(struct pci_dev *dev) {
|
|
#ifdef _WIN32
|
|
int i;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
u32 saved_bar, size;
|
|
|
|
if (dev->base_addr == 0)
|
|
continue;
|
|
|
|
saved_bar = pci_read_long(dev, PCI_BASE_ADDRESS_0 + i*4);
|
|
pci_write_long(dev, PCI_BASE_ADDRESS_0 + i*4, 0xFFFFFFFF);
|
|
size = pci_read_long(dev, PCI_BASE_ADDRESS_0 + i*4);
|
|
if (size & PCI_BASE_ADDRESS_SPACE_IO)
|
|
size = ~(size & PCI_BASE_ADDRESS_IO_MASK) & 0xFF;
|
|
else
|
|
size = ~(size & PCI_BASE_ADDRESS_MEM_MASK);
|
|
pci_write_long(dev, PCI_BASE_ADDRESS_0 + i*4, saved_bar);
|
|
|
|
dev->size[i] = size + 1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static int pci_board_open(board_t *board) {
|
|
if (board->mem_base != 0) {
|
|
#ifdef __linux__
|
|
board->base = mmap(0, board->len, PROT_READ | PROT_WRITE, MAP_SHARED, memfd, board->mem_base);
|
|
#elif _WIN32
|
|
board->base = map_memory(board->mem_base, board->len, &(board->mem_handle));
|
|
#endif
|
|
}
|
|
|
|
if (board->flash != BOARD_FLASH_NONE) {
|
|
eeprom_init(&(board->llio));
|
|
board->flash_id = read_flash_id(&(board->llio));
|
|
if (board->fallback_support == 1) {
|
|
eeprom_prepare_boot_block(board->flash_id);
|
|
board->flash_start_address = eeprom_calc_user_space(board->flash_id);
|
|
} else {
|
|
board->flash_start_address = 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int pci_board_close(board_t *board) {
|
|
if (board->base) {
|
|
#ifdef __linux__
|
|
munmap(board->base, board->len);
|
|
#elif _WIN32
|
|
unmap_memory(&(board->mem_handle));
|
|
#endif
|
|
}
|
|
eeprom_cleanup(&(board->llio));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int pci_boards_init(board_access_t *access) {
|
|
int eno;
|
|
|
|
#ifdef __linux__
|
|
if (seteuid(0) != 0) {
|
|
printf("You need root privileges (or setuid root) to access PCI hardware\n");
|
|
return -1;
|
|
}
|
|
pacc = pci_alloc();
|
|
pci_init(pacc); // inicjowanie biblioteki libpci
|
|
|
|
memfd = open("/dev/mem", O_RDWR);
|
|
eno = errno;
|
|
seteuid(getuid());
|
|
if (memfd < 0) {
|
|
printf("%s can't open /dev/mem: %s", __func__, strerror(eno));
|
|
return -1;
|
|
}
|
|
iopl(3);
|
|
#elif _WIN32
|
|
init_io_library();
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
void pci_boards_cleanup(board_access_t *access) {
|
|
#ifdef __linux__
|
|
close(memfd);
|
|
#elif _WIN32
|
|
release_io_library();
|
|
#endif
|
|
pci_cleanup(pacc);
|
|
}
|
|
|
|
void pci_boards_scan(board_access_t *access) {
|
|
struct pci_dev *dev;
|
|
board_t *board;
|
|
|
|
pci_scan_bus(pacc);
|
|
|
|
for (dev = pacc->devices; dev != NULL; dev = dev->next)
|
|
// first run - fill data struct
|
|
pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_CLASS);
|
|
|
|
if (access->recover == 1) {
|
|
for (dev = pacc->devices; dev != NULL; dev = dev->next) {
|
|
board = &boards[boards_count];
|
|
board_init_struct(board);
|
|
if ((dev->vendor_id == VENDORID_XIO2001) && (dev->device_id == DEVICEID_XIO2001)) {
|
|
board->type = BOARD_PCI;
|
|
strncpy(board->llio.board_name, "6I25 (RECOVER)", 14);
|
|
board->llio.num_ioport_connectors = 2;
|
|
board->llio.pins_per_connector = 17;
|
|
board->llio.ioport_connector_name[0] = "P3";
|
|
board->llio.ioport_connector_name[1] = "P2";
|
|
board->llio.fpga_part_number = "6slx9tqg144";
|
|
board->llio.num_leds = 2;
|
|
board->llio.write_flash = &local_write_flash;
|
|
board->llio.verify_flash = &local_verify_flash;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
board->mem_base = 0;
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_GPIO;
|
|
board->fallback_support = 1;
|
|
board->recover = 1;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
for (dev = pacc->devices; dev != NULL; dev = dev->next) {
|
|
board = &boards[boards_count];
|
|
board_init_struct(board);
|
|
|
|
if (dev->vendor_id == VENDORID_MESAPCI) {
|
|
if (dev->device_id == DEVICEID_MESA4I74) {
|
|
board->type = BOARD_PCI;
|
|
strncpy((char *) board->llio.board_name, "4I74", 4);
|
|
board->llio.num_ioport_connectors = 3;
|
|
board->llio.pins_per_connector = 24;
|
|
board->llio.ioport_connector_name[0] = "P1";
|
|
board->llio.ioport_connector_name[1] = "P3";
|
|
board->llio.ioport_connector_name[2] = "P4";
|
|
board->llio.fpga_part_number = "6slx9tqg144";
|
|
board->llio.num_leds = 0;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.write_flash = &local_write_flash;
|
|
board->llio.verify_flash = &local_verify_flash;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[0] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[0];
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_HM2;
|
|
board->fallback_support = 1;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
} else if (dev->device_id == DEVICEID_MESA5I24) {
|
|
board->type = BOARD_PCI;
|
|
strncpy((char *) board->llio.board_name, "5I24", 4);
|
|
board->llio.num_ioport_connectors = 3;
|
|
board->llio.pins_per_connector = 24;
|
|
board->llio.ioport_connector_name[0] = "P4";
|
|
board->llio.ioport_connector_name[1] = "P3";
|
|
board->llio.ioport_connector_name[2] = "P2";
|
|
board->llio.fpga_part_number = "6slx16ftg256 | 6slx25ftg256";
|
|
board->llio.num_leds = 4;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.write_flash = &local_write_flash;
|
|
board->llio.verify_flash = &local_verify_flash;
|
|
board->llio.reload = &pci_board_reload;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[0] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[0];
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_HM2;
|
|
board->fallback_support = 1;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
} else if (dev->device_id == DEVICEID_MESA5I25) {
|
|
board->type = BOARD_PCI;
|
|
strncpy((char *) board->llio.board_name, "5I25", 4);
|
|
board->llio.num_ioport_connectors = 2;
|
|
board->llio.pins_per_connector = 17;
|
|
board->llio.ioport_connector_name[0] = "P3";
|
|
board->llio.ioport_connector_name[1] = "P2";
|
|
board->llio.fpga_part_number = "6slx9tqg144";
|
|
board->llio.num_leds = 2;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.write_flash = &local_write_flash;
|
|
board->llio.verify_flash = &local_verify_flash;
|
|
board->llio.reload = &pci_board_reload;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[0] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[0];
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_HM2;
|
|
board->fallback_support = 1;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
} else if (dev->device_id == DEVICEID_MESA6I24) {
|
|
board->type = BOARD_PCI;
|
|
strncpy((char *) board->llio.board_name, "6I24", 4);
|
|
board->llio.num_ioport_connectors = 3;
|
|
board->llio.pins_per_connector = 24;
|
|
board->llio.ioport_connector_name[0] = "P4";
|
|
board->llio.ioport_connector_name[1] = "P3";
|
|
board->llio.ioport_connector_name[2] = "P2";
|
|
board->llio.fpga_part_number = "6slx16ftg256 | 6slx25ftg256";
|
|
board->llio.num_leds = 4;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.write_flash = &local_write_flash;
|
|
board->llio.verify_flash = &local_verify_flash;
|
|
board->llio.reload = &pci_board_reload;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[0] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[0];
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_HM2;
|
|
board->fallback_support = 1;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
} else if (dev->device_id == DEVICEID_MESA6I25) {
|
|
board->type = BOARD_PCI;
|
|
strncpy(board->llio.board_name, "6I25", 4);
|
|
board->llio.num_ioport_connectors = 2;
|
|
board->llio.pins_per_connector = 17;
|
|
board->llio.ioport_connector_name[0] = "P3";
|
|
board->llio.ioport_connector_name[1] = "P2";
|
|
board->llio.fpga_part_number = "6slx9tqg144";
|
|
board->llio.num_leds = 2;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.write_flash = &local_write_flash;
|
|
board->llio.verify_flash = &local_verify_flash;
|
|
board->llio.reload = &pci_board_reload;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[0] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[0];
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_HM2;
|
|
board->fallback_support = 1;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
}
|
|
} else if (dev->vendor_id == VENDORID_PLX) {
|
|
if (dev->device_id == DEVICEID_PLX9030) {
|
|
u16 ssid = pci_read_word(dev, PCI_SUBSYSTEM_ID);
|
|
if (ssid == SUBDEVICEID_MESA5I20) {
|
|
board->type = BOARD_PCI;
|
|
strncpy(board->llio.board_name, "5I20", 4);
|
|
board->llio.num_ioport_connectors = 3;
|
|
board->llio.pins_per_connector = 24;
|
|
board->llio.ioport_connector_name[0] = "P2";
|
|
board->llio.ioport_connector_name[1] = "P3";
|
|
board->llio.ioport_connector_name[2] = "P4";
|
|
board->llio.fpga_part_number = "2s200pq208";
|
|
board->llio.num_leds = 8;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.program_fpga = &plx9030_program_fpga;
|
|
board->llio.reset = &plx9030_reset;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[5] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[5];
|
|
board->ctrl_base_addr = dev->base_addr[1] & PCI_ADDR_IO_MASK;
|
|
board->data_base_addr = dev->base_addr[2] & PCI_ADDR_IO_MASK;
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_NONE;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
// fix up LASxBRD READY if needed
|
|
plx9030_fixup_LASxBRD_READY(&(board->llio));
|
|
} else if (ssid == SUBDEVICEID_MESA4I65) {
|
|
board->type = BOARD_PCI;
|
|
strncpy(board->llio.board_name, "4I65", 4);
|
|
board->llio.num_ioport_connectors = 3;
|
|
board->llio.pins_per_connector = 24;
|
|
board->llio.ioport_connector_name[0] = "P1";
|
|
board->llio.ioport_connector_name[1] = "P3";
|
|
board->llio.ioport_connector_name[2] = "P4";
|
|
board->llio.fpga_part_number = "2s200pq208";
|
|
board->llio.num_leds = 8;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.program_fpga = &plx9030_program_fpga;
|
|
board->llio.reset = &plx9030_reset;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[5] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[5];
|
|
board->ctrl_base_addr = dev->base_addr[1] & PCI_ADDR_IO_MASK;
|
|
board->data_base_addr = dev->base_addr[2] & PCI_ADDR_IO_MASK;
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_NONE;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
// fix up LASxBRD READY if needed
|
|
plx9030_fixup_LASxBRD_READY(&(board->llio));
|
|
}
|
|
} else if (dev->device_id == DEVICEID_PLX9054) {
|
|
u16 ssid = pci_read_word(dev, PCI_SUBSYSTEM_ID);
|
|
if ((ssid == SUBDEVICEID_MESA4I68_OLD) || (ssid == SUBDEVICEID_MESA4I68)) {
|
|
board->type = BOARD_PCI;
|
|
strncpy(board->llio.board_name, "4I68", 4);
|
|
board->llio.num_ioport_connectors = 3;
|
|
board->llio.pins_per_connector = 24;
|
|
board->llio.ioport_connector_name[0] = "P1";
|
|
board->llio.ioport_connector_name[1] = "P2";
|
|
board->llio.ioport_connector_name[2] = "P4";
|
|
board->llio.fpga_part_number = "3s400pq208";
|
|
board->llio.num_leds = 4;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.program_fpga = &plx905x_program_fpga;
|
|
board->llio.reset = &plx905x_reset;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[3] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[3];
|
|
board->ctrl_base_addr = dev->base_addr[1] & PCI_ADDR_IO_MASK;
|
|
board->data_base_addr = dev->base_addr[2] & PCI_ADDR_IO_MASK;
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_NONE;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
} else if (ssid == SUBDEVICEID_MESA5I21) {
|
|
board->type = BOARD_PCI;
|
|
strncpy(board->llio.board_name, "5I21", 4);
|
|
board->llio.num_ioport_connectors = 2;
|
|
board->llio.pins_per_connector = 32;
|
|
board->llio.ioport_connector_name[0] = "P1";
|
|
board->llio.ioport_connector_name[1] = "P1";
|
|
board->llio.fpga_part_number = "3s400pq208";
|
|
board->llio.num_leds = 8;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.program_fpga = &plx905x_program_fpga;
|
|
board->llio.reset = &plx905x_reset;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[3] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[3];
|
|
board->ctrl_base_addr = dev->base_addr[1] & PCI_ADDR_IO_MASK;
|
|
board->data_base_addr = dev->base_addr[2] & PCI_ADDR_IO_MASK;
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_NONE;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
} else if ((ssid == SUBDEVICEID_MESA5I22_10) || (ssid == SUBDEVICEID_MESA5I22_15)) {
|
|
board->type = BOARD_PCI;
|
|
strncpy(board->llio.board_name, "5I22", 4);
|
|
board->llio.num_ioport_connectors = 4;
|
|
board->llio.pins_per_connector = 24;
|
|
board->llio.ioport_connector_name[0] = "P2";
|
|
board->llio.ioport_connector_name[1] = "P3";
|
|
board->llio.ioport_connector_name[2] = "P4";
|
|
board->llio.ioport_connector_name[3] = "P5";
|
|
if (ssid == SUBDEVICEID_MESA5I22_10) {
|
|
board->llio.fpga_part_number = "3s1000fg320";
|
|
} else if (ssid == SUBDEVICEID_MESA5I22_15) {
|
|
board->llio.fpga_part_number = "3s1500fg320";
|
|
}
|
|
board->llio.num_leds = 8;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.program_fpga = &plx905x_program_fpga;
|
|
board->llio.reset = &plx905x_reset;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[3] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[3];
|
|
board->ctrl_base_addr = dev->base_addr[1] & PCI_ADDR_IO_MASK;
|
|
board->data_base_addr = dev->base_addr[2] & PCI_ADDR_IO_MASK;
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_NONE;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
} else if (ssid == SUBDEVICEID_MESA5I23) {
|
|
board->type = BOARD_PCI;
|
|
strncpy(board->llio.board_name, "5I23", 4);
|
|
board->llio.num_ioport_connectors = 3;
|
|
board->llio.pins_per_connector = 24;
|
|
board->llio.ioport_connector_name[0] = "P2";
|
|
board->llio.ioport_connector_name[1] = "P3";
|
|
board->llio.ioport_connector_name[2] = "P4";
|
|
board->llio.fpga_part_number = "3s400pq208";
|
|
board->llio.num_leds = 2;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.program_fpga = &plx905x_program_fpga;
|
|
board->llio.reset = &plx905x_reset;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[3] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[3];
|
|
board->ctrl_base_addr = dev->base_addr[1] & PCI_ADDR_IO_MASK;
|
|
board->data_base_addr = dev->base_addr[2] & PCI_ADDR_IO_MASK;
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_NONE;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
} else if ((ssid == SUBDEVICEID_MESA4I69_16) || (ssid == SUBDEVICEID_MESA4I69_25)) {
|
|
board->type = BOARD_PCI;
|
|
strncpy(board->llio.board_name, "4I69", 4);
|
|
board->llio.num_ioport_connectors = 3;
|
|
board->llio.pins_per_connector = 24;
|
|
board->llio.ioport_connector_name[0] = "P1";
|
|
board->llio.ioport_connector_name[1] = "P3";
|
|
board->llio.ioport_connector_name[2] = "P4";
|
|
if (ssid == SUBDEVICEID_MESA4I69_16) {
|
|
board->llio.fpga_part_number = "6slx16ftg256";
|
|
} else if (ssid == SUBDEVICEID_MESA4I69_25) {
|
|
board->llio.fpga_part_number = "6slx25ftg256";
|
|
}
|
|
board->llio.num_leds = 8;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.program_fpga = &plx905x_program_fpga;
|
|
board->llio.reset = &plx905x_reset;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[3] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[3];
|
|
board->ctrl_base_addr = dev->base_addr[1] & PCI_ADDR_IO_MASK;
|
|
board->data_base_addr = dev->base_addr[2] & PCI_ADDR_IO_MASK;
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_NONE;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
}
|
|
} else if (dev->device_id == DEVICEID_PLX9056) {
|
|
u16 ssid = pci_read_word(dev, PCI_SUBSYSTEM_ID);
|
|
if ((ssid == SUBDEVICEID_MESA3X20_10) || (ssid == SUBDEVICEID_MESA3X20_15) || (ssid == SUBDEVICEID_MESA3X20_20)) {
|
|
board->type = BOARD_PCI;
|
|
strncpy(board->llio.board_name, "3X20", 4);
|
|
board->llio.num_ioport_connectors = 6;
|
|
board->llio.pins_per_connector = 24;
|
|
board->llio.ioport_connector_name[0] = "P4";
|
|
board->llio.ioport_connector_name[1] = "P5";
|
|
board->llio.ioport_connector_name[2] = "P6";
|
|
board->llio.ioport_connector_name[3] = "P9";
|
|
board->llio.ioport_connector_name[4] = "P8";
|
|
board->llio.ioport_connector_name[5] = "P7";
|
|
if (ssid == SUBDEVICEID_MESA3X20_10) {
|
|
board->llio.fpga_part_number = "3s1000fg456";
|
|
} else if (ssid == SUBDEVICEID_MESA3X20_15) {
|
|
board->llio.fpga_part_number = "3s1500fg456";
|
|
} else if (ssid == SUBDEVICEID_MESA3X20_20) {
|
|
board->llio.fpga_part_number = "3s2000fg456";
|
|
}
|
|
board->llio.num_leds = 0;
|
|
board->llio.read = &pci_read;
|
|
board->llio.write = &pci_write;
|
|
board->llio.program_fpga = &plx905x_program_fpga;
|
|
board->llio.reset = &plx905x_reset;
|
|
board->llio.write_flash = &local_write_flash;
|
|
board->llio.verify_flash = &local_verify_flash;
|
|
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
pci_fix_bar_lengths(dev);
|
|
board->mem_base = dev->base_addr[3] & PCI_ADDR_MEM_MASK;
|
|
board->len = dev->size[3];
|
|
board->ctrl_base_addr = dev->base_addr[1] & PCI_ADDR_IO_MASK;
|
|
board->data_base_addr = dev->base_addr[2] & PCI_ADDR_IO_MASK;
|
|
board->dev = dev;
|
|
board->flash = BOARD_FLASH_IO;
|
|
board->fallback_support = 0;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
}
|
|
} else if (dev->device_id == DEVICEID_PLX8112) {
|
|
board->type = BOARD_PCI;
|
|
strncpy(board->llio.board_name, "5I71", 4);
|
|
board->open = &pci_board_open;
|
|
board->close = &pci_board_close;
|
|
board->print_info = &pci_print_info;
|
|
board->dev = dev;
|
|
board->llio.verbose = access->verbose;
|
|
|
|
boards_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void pci_print_info(board_t *board) {
|
|
int i;
|
|
|
|
printf("\nPCI device %s at %04X:%02X:%02X.%1X\n",
|
|
board->llio.board_name, board->dev->domain, board->dev->bus, board->dev->dev, board->dev->func);
|
|
if (board->llio.verbose == 0)
|
|
return;
|
|
|
|
printf(" Device ID [%04X:%04X], Subsystem device ID [%04X:%04X]\n",
|
|
board->dev->vendor_id, board->dev->device_id,
|
|
pci_read_word(board->dev, PCI_SUBSYSTEM_VENDOR_ID), pci_read_word(board->dev, PCI_SUBSYSTEM_ID));
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
u32 flags = pci_read_long(board->dev, PCI_BASE_ADDRESS_0 + 4*i);
|
|
if (board->dev->base_addr[i] != 0) {
|
|
if (flags & PCI_BASE_ADDRESS_SPACE_IO) {
|
|
printf(" Region %d: I/O at %04X", i, (unsigned int) (board->dev->base_addr[i] & PCI_BASE_ADDRESS_IO_MASK));
|
|
show_formatted_size(board->dev->size[i]);
|
|
printf("\n");
|
|
} else {
|
|
printf(" Region %d: Memory at %08X", i, (unsigned int) board->dev->base_addr[i]);
|
|
show_formatted_size(board->dev->size[i]);
|
|
printf("\n");
|
|
}
|
|
}
|
|
}
|
|
printf("Communication:\n");
|
|
if (board->ctrl_base_addr > 0)
|
|
printf(" Ctrl I/O addr: %04X\n", board->ctrl_base_addr);
|
|
if (board->data_base_addr > 0)
|
|
printf(" Data I/O addr: %04X\n", board->data_base_addr);
|
|
if (board->mem_base > 0)
|
|
printf(" Memory: %08X\n", board->mem_base);
|
|
|
|
show_board_info(board);
|
|
}
|