hm2_pci.c
来自「CNC 的开放码,EMC2 V2.2.8版」· C语言 代码 · 共 577 行 · 第 1/2 页
C
577 行
//// Copyright (C) 2007-2008 Sebastian Kuzminsky//// 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//#include <linux/pci.h>#include "rtapi.h"#include "rtapi_app.h"#include "rtapi_string.h"#include "hal.h"#include "hostmot2-lowlevel.h"#include "hm2_pci.h"MODULE_LICENSE("GPL");MODULE_AUTHOR("Sebastian Kuzminsky");MODULE_DESCRIPTION("Driver for HostMot2 on the 5i20, 4i65, and 5i22 Anything I/O boards from Mesa Electronics");MODULE_SUPPORTED_DEVICE("Mesa-AnythingIO-5i20"); // FIXMEstatic char *config[HM2_PCI_MAX_BOARDS];static int num_config_strings = HM2_PCI_MAX_BOARDS;module_param_array(config, charp, &num_config_strings, S_IRUGO);MODULE_PARM_DESC(config, "config string for the AnyIO boards (see hostmot2(9) manpage)");static int comp_id;// FIXME: should probably have a linked list of boards instead of an arraystatic hm2_pci_t hm2_pci_board[HM2_PCI_MAX_BOARDS];static int num_boards = 0;static int num_5i20 = 0;static int num_5i22 = 0;static int num_5i23 = 0;static int num_4i65 = 0;static int num_4i68 = 0;static struct pci_device_id hm2_pci_tbl[] = { // 5i20 { .vendor = 0x10b5, .device = HM2_PCI_DEV_PLX9030, .subvendor = 0x10b5, .subdevice = HM2_PCI_SSDEV_5I20, }, // 4i65 { .vendor = 0x10b5, .device = HM2_PCI_DEV_PLX9030, .subvendor = 0x10b5, .subdevice = HM2_PCI_SSDEV_4I65, }, // 5i22-1.0M { .vendor = 0x10b5, .device = HM2_PCI_DEV_PLX9054, .subvendor = 0x10b5, .subdevice = HM2_PCI_SSDEV_5I22_10, }, // 5i22-1.5M { .vendor = 0x10b5, .device = HM2_PCI_DEV_PLX9054, .subvendor = 0x10b5, .subdevice = HM2_PCI_SSDEV_5I22_15, }, // 5i23 { .vendor = 0x10b5, .device = HM2_PCI_DEV_PLX9054, .subvendor = 0x10b5, .subdevice = HM2_PCI_SSDEV_5I23, }, // 4i68 (old SSID) { .vendor = 0x10b5, .device = HM2_PCI_DEV_PLX9054, .subvendor = 0x10b5, .subdevice = HM2_PCI_SSDEV_4I68_OLD, }, // 4i68 (new SSID) { .vendor = 0x10b5, .device = HM2_PCI_DEV_PLX9054, .subvendor = 0x10b5, .subdevice = HM2_PCI_SSDEV_4I68, }, {0,},};MODULE_DEVICE_TABLE(pci, hm2_pci_tbl);// // these are the "low-level I/O" functions exported up//static int hm2_pci_read(hm2_lowlevel_io_t *this, u32 addr, void *buffer, int size) { hm2_pci_t *board = this->private; memcpy(buffer, (board->base + addr), size); return 1; // success}static int hm2_pci_write(hm2_lowlevel_io_t *this, u32 addr, void *buffer, int size) { hm2_pci_t *board = this->private; memcpy((board->base + addr), buffer, size); return 1; // success}static int hm2_plx9030_program_fpga(hm2_lowlevel_io_t *this, const bitfile_t *bitfile) { hm2_pci_t *board = this->private; int i; u32 status, control; // set /WRITE low for data transfer, and turn on LED status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET); control = status & ~_WRITE_MASK & ~_LED_MASK; outl(control, board->ctrl_base_addr + CTRL_STAT_OFFSET); // program the FPGA for (i = 0; i < bitfile->e.size; i ++) { outb(bitfile->e.data[i], board->data_base_addr); } // all bytes transferred, make sure FPGA is all set up now status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET); if (!(status & _INIT_MASK)) { // /INIT goes low on CRC error THIS_ERR("FPGA asserted /INIT: CRC error\n"); goto fail; } if (!(status & DONE_MASK)) { THIS_ERR("FPGA did not assert DONE\n"); goto fail; } // turn off write enable and LED control = status | _WRITE_MASK | _LED_MASK; outl(control, board->ctrl_base_addr + CTRL_STAT_OFFSET); return 0;fail: // set /PROGRAM low (reset device), /WRITE high and LED off status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET); control = status & ~_PROGRAM_MASK; control |= _WRITE_MASK | _LED_MASK; outl(control, board->ctrl_base_addr + CTRL_STAT_OFFSET); return -EIO;}static int hm2_plx9030_reset(hm2_lowlevel_io_t *this) { hm2_pci_t *board = this->private; u32 status; u32 control; status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET); // set /PROGRAM bit low to reset the FPGA control = status & ~_PROGRAM_MASK; // set /WRITE and /LED high (idle state) control |= _WRITE_MASK | _LED_MASK; // and write it back outl(control, board->ctrl_base_addr + CTRL_STAT_OFFSET); // verify that /INIT and DONE went low status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET); if (status & (DONE_MASK | _INIT_MASK)) { THIS_ERR( "FPGA did not reset: /INIT = %d, DONE = %d\n", (status & _INIT_MASK ? 1 : 0), (status & DONE_MASK ? 1 : 0) ); return -EIO; } // set /PROGRAM high, let FPGA come out of reset control = status | _PROGRAM_MASK; outl(control, board->ctrl_base_addr + 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 + CTRL_STAT_OFFSET); if (status & _INIT_MASK) break; } while (count-- > 0); if (count == 0) { THIS_ERR("FPGA did not come out of /INIT"); return -EIO; } } return 0;}// fix up LASxBRD READY if neededstatic void hm2_plx9030_fixup_LASxBRD_READY(hm2_pci_t *board) { hm2_lowlevel_io_t *this = &board->llio; int offsets[] = { LAS0BRD_OFFSET, LAS1BRD_OFFSET, LAS2BRD_OFFSET, 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 & LASxBRD_READY)) { THIS_INFO("LAS%dBRD #READY is off, enabling now\n", i); val |= LASxBRD_READY; outl(val, addr); } }}static int hm2_plx9054_program_fpga(hm2_lowlevel_io_t *this, const bitfile_t *bitfile) { hm2_pci_t *board = this->private; int i; u32 status; // program the FPGA for (i = 0; i < bitfile->e.size; i ++) { outb(bitfile->e.data[i], board->data_base_addr); } // all bytes transferred, make sure FPGA is all set up now for (i = 0; i < DONE_WAIT_5I22; i++) { status = inl(board->ctrl_base_addr + CTRL_STAT_OFFSET_5I22); if (status & DONE_MASK_5I22) break; } if (i >= DONE_WAIT_5I22) { THIS_ERR("Error: Not /DONE; programming not completed.\n"); return -EIO; } return 0;}static int hm2_plx9054_reset(hm2_lowlevel_io_t *this) { hm2_pci_t *board = this->private; int i; u32 status, control;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?