18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2008-2010 Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Derived from the ems_pci.c driver: 68c2ecf20Sopenharmony_ci * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2008 Markus Plessing <plessing@ems-wuensche.com> 88c2ecf20Sopenharmony_ci * Copyright (C) 2008 Sebastian Haas <haas@ems-wuensche.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci#include <linux/can/dev.h> 198c2ecf20Sopenharmony_ci#include <linux/io.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "sja1000.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define DRV_NAME "sja1000_plx_pci" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciMODULE_AUTHOR("Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>"); 268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with " 278c2ecf20Sopenharmony_ci "the SJA1000 chips"); 288c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, " 298c2ecf20Sopenharmony_ci "Adlink PCI-7841/cPCI-7841 SE, " 308c2ecf20Sopenharmony_ci "Marathon CAN-bus-PCI, " 318c2ecf20Sopenharmony_ci "Marathon CAN-bus-PCIe, " 328c2ecf20Sopenharmony_ci "TEWS TECHNOLOGIES TPMC810, " 338c2ecf20Sopenharmony_ci "esd CAN-PCI/CPCI/PCI104/200, " 348c2ecf20Sopenharmony_ci "esd CAN-PCI/PMC/266, " 358c2ecf20Sopenharmony_ci "esd CAN-PCIe/2000, " 368c2ecf20Sopenharmony_ci "Connect Tech Inc. CANpro/104-Plus Opto (CRG001), " 378c2ecf20Sopenharmony_ci "IXXAT PC-I 04/PCI, " 388c2ecf20Sopenharmony_ci "ELCUS CAN-200-PCI, " 398c2ecf20Sopenharmony_ci "ASEM DUAL CAN-RAW") 408c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define PLX_PCI_MAX_CHAN 2 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct plx_pci_card { 458c2ecf20Sopenharmony_ci int channels; /* detected channels count */ 468c2ecf20Sopenharmony_ci struct net_device *net_dev[PLX_PCI_MAX_CHAN]; 478c2ecf20Sopenharmony_ci void __iomem *conf_addr; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Pointer to device-dependent reset function */ 508c2ecf20Sopenharmony_ci void (*reset_func)(struct pci_dev *pdev); 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define PLX_PCI_CAN_CLOCK (16000000 / 2) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* PLX9030/9050/9052 registers */ 568c2ecf20Sopenharmony_ci#define PLX_INTCSR 0x4c /* Interrupt Control/Status */ 578c2ecf20Sopenharmony_ci#define PLX_CNTRL 0x50 /* User I/O, Direct Slave Response, 588c2ecf20Sopenharmony_ci * Serial EEPROM, and Initialization 598c2ecf20Sopenharmony_ci * Control register 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define PLX_LINT1_EN 0x1 /* Local interrupt 1 enable */ 638c2ecf20Sopenharmony_ci#define PLX_LINT1_POL (1 << 1) /* Local interrupt 1 polarity */ 648c2ecf20Sopenharmony_ci#define PLX_LINT2_EN (1 << 3) /* Local interrupt 2 enable */ 658c2ecf20Sopenharmony_ci#define PLX_LINT2_POL (1 << 4) /* Local interrupt 2 polarity */ 668c2ecf20Sopenharmony_ci#define PLX_PCI_INT_EN (1 << 6) /* PCI Interrupt Enable */ 678c2ecf20Sopenharmony_ci#define PLX_PCI_RESET (1 << 30) /* PCI Adapter Software Reset */ 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* PLX9056 registers */ 708c2ecf20Sopenharmony_ci#define PLX9056_INTCSR 0x68 /* Interrupt Control/Status */ 718c2ecf20Sopenharmony_ci#define PLX9056_CNTRL 0x6c /* Control / Software Reset */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define PLX9056_LINTI (1 << 11) 748c2ecf20Sopenharmony_ci#define PLX9056_PCI_INT_EN (1 << 8) 758c2ecf20Sopenharmony_ci#define PLX9056_PCI_RCR (1 << 29) /* Read Configuration Registers */ 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* 788c2ecf20Sopenharmony_ci * The board configuration is probably following: 798c2ecf20Sopenharmony_ci * RX1 is connected to ground. 808c2ecf20Sopenharmony_ci * TX1 is not connected. 818c2ecf20Sopenharmony_ci * CLKO is not connected. 828c2ecf20Sopenharmony_ci * Setting the OCR register to 0xDA is a good idea. 838c2ecf20Sopenharmony_ci * This means normal output mode, push-pull and the correct polarity. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci#define PLX_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* OCR setting for ASEM Dual CAN raw */ 888c2ecf20Sopenharmony_ci#define ASEM_PCI_OCR 0xfe 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* 918c2ecf20Sopenharmony_ci * In the CDR register, you should set CBP to 1. 928c2ecf20Sopenharmony_ci * You will probably also want to set the clock divider value to 7 938c2ecf20Sopenharmony_ci * (meaning direct oscillator output) because the second SJA1000 chip 948c2ecf20Sopenharmony_ci * is driven by the first one CLKOUT output. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci#define PLX_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* SJA1000 Control Register in the BasicCAN Mode */ 998c2ecf20Sopenharmony_ci#define REG_CR 0x00 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* States of some SJA1000 registers after hardware reset in the BasicCAN mode*/ 1028c2ecf20Sopenharmony_ci#define REG_CR_BASICCAN_INITIAL 0x21 1038c2ecf20Sopenharmony_ci#define REG_CR_BASICCAN_INITIAL_MASK 0xa1 1048c2ecf20Sopenharmony_ci#define REG_SR_BASICCAN_INITIAL 0x0c 1058c2ecf20Sopenharmony_ci#define REG_IR_BASICCAN_INITIAL 0xe0 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* States of some SJA1000 registers after hardware reset in the PeliCAN mode*/ 1088c2ecf20Sopenharmony_ci#define REG_MOD_PELICAN_INITIAL 0x01 1098c2ecf20Sopenharmony_ci#define REG_SR_PELICAN_INITIAL 0x3c 1108c2ecf20Sopenharmony_ci#define REG_IR_PELICAN_INITIAL 0x00 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define ADLINK_PCI_VENDOR_ID 0x144A 1138c2ecf20Sopenharmony_ci#define ADLINK_PCI_DEVICE_ID 0x7841 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#define ESD_PCI_SUB_SYS_ID_PCI200 0x0004 1168c2ecf20Sopenharmony_ci#define ESD_PCI_SUB_SYS_ID_PCI266 0x0009 1178c2ecf20Sopenharmony_ci#define ESD_PCI_SUB_SYS_ID_PMC266 0x000e 1188c2ecf20Sopenharmony_ci#define ESD_PCI_SUB_SYS_ID_CPCI200 0x010b 1198c2ecf20Sopenharmony_ci#define ESD_PCI_SUB_SYS_ID_PCIE2000 0x0200 1208c2ecf20Sopenharmony_ci#define ESD_PCI_SUB_SYS_ID_PCI104200 0x0501 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define CAN200PCI_DEVICE_ID 0x9030 1238c2ecf20Sopenharmony_ci#define CAN200PCI_VENDOR_ID 0x10b5 1248c2ecf20Sopenharmony_ci#define CAN200PCI_SUB_DEVICE_ID 0x0301 1258c2ecf20Sopenharmony_ci#define CAN200PCI_SUB_VENDOR_ID 0xe1c5 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci#define IXXAT_PCI_VENDOR_ID 0x10b5 1288c2ecf20Sopenharmony_ci#define IXXAT_PCI_DEVICE_ID 0x9050 1298c2ecf20Sopenharmony_ci#define IXXAT_PCI_SUB_SYS_ID 0x2540 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define MARATHON_PCI_DEVICE_ID 0x2715 1328c2ecf20Sopenharmony_ci#define MARATHON_PCIE_DEVICE_ID 0x3432 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#define TEWS_PCI_VENDOR_ID 0x1498 1358c2ecf20Sopenharmony_ci#define TEWS_PCI_DEVICE_ID_TMPC810 0x032A 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci#define CTI_PCI_VENDOR_ID 0x12c4 1388c2ecf20Sopenharmony_ci#define CTI_PCI_DEVICE_ID_CRG001 0x0900 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci#define MOXA_PCI_VENDOR_ID 0x1393 1418c2ecf20Sopenharmony_ci#define MOXA_PCI_DEVICE_ID 0x0100 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#define ASEM_RAW_CAN_VENDOR_ID 0x10b5 1448c2ecf20Sopenharmony_ci#define ASEM_RAW_CAN_DEVICE_ID 0x9030 1458c2ecf20Sopenharmony_ci#define ASEM_RAW_CAN_SUB_VENDOR_ID 0x3000 1468c2ecf20Sopenharmony_ci#define ASEM_RAW_CAN_SUB_DEVICE_ID 0x1001 1478c2ecf20Sopenharmony_ci#define ASEM_RAW_CAN_SUB_DEVICE_ID_BIS 0x1002 1488c2ecf20Sopenharmony_ci#define ASEM_RAW_CAN_RST_REGISTER 0x54 1498c2ecf20Sopenharmony_ci#define ASEM_RAW_CAN_RST_MASK_CAN1 0x20 1508c2ecf20Sopenharmony_ci#define ASEM_RAW_CAN_RST_MASK_CAN2 0x04 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic void plx_pci_reset_common(struct pci_dev *pdev); 1538c2ecf20Sopenharmony_cistatic void plx9056_pci_reset_common(struct pci_dev *pdev); 1548c2ecf20Sopenharmony_cistatic void plx_pci_reset_marathon_pci(struct pci_dev *pdev); 1558c2ecf20Sopenharmony_cistatic void plx_pci_reset_marathon_pcie(struct pci_dev *pdev); 1568c2ecf20Sopenharmony_cistatic void plx_pci_reset_asem_dual_can_raw(struct pci_dev *pdev); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistruct plx_pci_channel_map { 1598c2ecf20Sopenharmony_ci u32 bar; 1608c2ecf20Sopenharmony_ci u32 offset; 1618c2ecf20Sopenharmony_ci u32 size; /* 0x00 - auto, e.g. length of entire bar */ 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistruct plx_pci_card_info { 1658c2ecf20Sopenharmony_ci const char *name; 1668c2ecf20Sopenharmony_ci int channel_count; 1678c2ecf20Sopenharmony_ci u32 can_clock; 1688c2ecf20Sopenharmony_ci u8 ocr; /* output control register */ 1698c2ecf20Sopenharmony_ci u8 cdr; /* clock divider register */ 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Parameters for mapping local configuration space */ 1728c2ecf20Sopenharmony_ci struct plx_pci_channel_map conf_map; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* Parameters for mapping the SJA1000 chips */ 1758c2ecf20Sopenharmony_ci struct plx_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CHAN]; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* Pointer to device-dependent reset function */ 1788c2ecf20Sopenharmony_ci void (*reset_func)(struct pci_dev *pdev); 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_adlink = { 1828c2ecf20Sopenharmony_ci "Adlink PCI-7841/cPCI-7841", 2, 1838c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, 1848c2ecf20Sopenharmony_ci {1, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} }, 1858c2ecf20Sopenharmony_ci &plx_pci_reset_common 1868c2ecf20Sopenharmony_ci /* based on PLX9052 */ 1878c2ecf20Sopenharmony_ci}; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_adlink_se = { 1908c2ecf20Sopenharmony_ci "Adlink PCI-7841/cPCI-7841 SE", 2, 1918c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, 1928c2ecf20Sopenharmony_ci {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} }, 1938c2ecf20Sopenharmony_ci &plx_pci_reset_common 1948c2ecf20Sopenharmony_ci /* based on PLX9052 */ 1958c2ecf20Sopenharmony_ci}; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_esd200 = { 1988c2ecf20Sopenharmony_ci "esd CAN-PCI/CPCI/PCI104/200", 2, 1998c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, 2008c2ecf20Sopenharmony_ci {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} }, 2018c2ecf20Sopenharmony_ci &plx_pci_reset_common 2028c2ecf20Sopenharmony_ci /* based on PLX9030/9050 */ 2038c2ecf20Sopenharmony_ci}; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_esd266 = { 2068c2ecf20Sopenharmony_ci "esd CAN-PCI/PMC/266", 2, 2078c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, 2088c2ecf20Sopenharmony_ci {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} }, 2098c2ecf20Sopenharmony_ci &plx9056_pci_reset_common 2108c2ecf20Sopenharmony_ci /* based on PLX9056 */ 2118c2ecf20Sopenharmony_ci}; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_esd2000 = { 2148c2ecf20Sopenharmony_ci "esd CAN-PCIe/2000", 2, 2158c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, 2168c2ecf20Sopenharmony_ci {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} }, 2178c2ecf20Sopenharmony_ci &plx9056_pci_reset_common 2188c2ecf20Sopenharmony_ci /* based on PEX8311 */ 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_ixxat = { 2228c2ecf20Sopenharmony_ci "IXXAT PC-I 04/PCI", 2, 2238c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, 2248c2ecf20Sopenharmony_ci {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x200, 0x80} }, 2258c2ecf20Sopenharmony_ci &plx_pci_reset_common 2268c2ecf20Sopenharmony_ci /* based on PLX9050 */ 2278c2ecf20Sopenharmony_ci}; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_marathon_pci = { 2308c2ecf20Sopenharmony_ci "Marathon CAN-bus-PCI", 2, 2318c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, 2328c2ecf20Sopenharmony_ci {0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} }, 2338c2ecf20Sopenharmony_ci &plx_pci_reset_marathon_pci 2348c2ecf20Sopenharmony_ci /* based on PLX9052 */ 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_marathon_pcie = { 2388c2ecf20Sopenharmony_ci "Marathon CAN-bus-PCIe", 2, 2398c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, 2408c2ecf20Sopenharmony_ci {0, 0x00, 0x00}, { {2, 0x00, 0x00}, {3, 0x80, 0x00} }, 2418c2ecf20Sopenharmony_ci &plx_pci_reset_marathon_pcie 2428c2ecf20Sopenharmony_ci /* based on PEX8311 */ 2438c2ecf20Sopenharmony_ci}; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_tews = { 2468c2ecf20Sopenharmony_ci "TEWS TECHNOLOGIES TPMC810", 2, 2478c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, 2488c2ecf20Sopenharmony_ci {0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} }, 2498c2ecf20Sopenharmony_ci &plx_pci_reset_common 2508c2ecf20Sopenharmony_ci /* based on PLX9030 */ 2518c2ecf20Sopenharmony_ci}; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_cti = { 2548c2ecf20Sopenharmony_ci "Connect Tech Inc. CANpro/104-Plus Opto (CRG001)", 2, 2558c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, 2568c2ecf20Sopenharmony_ci {0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} }, 2578c2ecf20Sopenharmony_ci &plx_pci_reset_common 2588c2ecf20Sopenharmony_ci /* based on PLX9030 */ 2598c2ecf20Sopenharmony_ci}; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_elcus = { 2628c2ecf20Sopenharmony_ci "Eclus CAN-200-PCI", 2, 2638c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, 2648c2ecf20Sopenharmony_ci {1, 0x00, 0x00}, { {2, 0x00, 0x80}, {3, 0x00, 0x80} }, 2658c2ecf20Sopenharmony_ci &plx_pci_reset_common 2668c2ecf20Sopenharmony_ci /* based on PLX9030 */ 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_moxa = { 2708c2ecf20Sopenharmony_ci "MOXA", 2, 2718c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, 2728c2ecf20Sopenharmony_ci {0, 0x00, 0x00}, { {0, 0x00, 0x80}, {1, 0x00, 0x80} }, 2738c2ecf20Sopenharmony_ci &plx_pci_reset_common 2748c2ecf20Sopenharmony_ci /* based on PLX9052 */ 2758c2ecf20Sopenharmony_ci}; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic struct plx_pci_card_info plx_pci_card_info_asem_dual_can = { 2788c2ecf20Sopenharmony_ci "ASEM Dual CAN raw PCI", 2, 2798c2ecf20Sopenharmony_ci PLX_PCI_CAN_CLOCK, ASEM_PCI_OCR, PLX_PCI_CDR, 2808c2ecf20Sopenharmony_ci {0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} }, 2818c2ecf20Sopenharmony_ci &plx_pci_reset_asem_dual_can_raw 2828c2ecf20Sopenharmony_ci /* based on PLX9030 */ 2838c2ecf20Sopenharmony_ci}; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic const struct pci_device_id plx_pci_tbl[] = { 2868c2ecf20Sopenharmony_ci { 2878c2ecf20Sopenharmony_ci /* Adlink PCI-7841/cPCI-7841 */ 2888c2ecf20Sopenharmony_ci ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID, 2898c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 2908c2ecf20Sopenharmony_ci PCI_CLASS_NETWORK_OTHER << 8, ~0, 2918c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_adlink 2928c2ecf20Sopenharmony_ci }, 2938c2ecf20Sopenharmony_ci { 2948c2ecf20Sopenharmony_ci /* Adlink PCI-7841/cPCI-7841 SE */ 2958c2ecf20Sopenharmony_ci ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID, 2968c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 2978c2ecf20Sopenharmony_ci PCI_CLASS_COMMUNICATION_OTHER << 8, ~0, 2988c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_adlink_se 2998c2ecf20Sopenharmony_ci }, 3008c2ecf20Sopenharmony_ci { 3018c2ecf20Sopenharmony_ci /* esd CAN-PCI/200 */ 3028c2ecf20Sopenharmony_ci PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, 3038c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PCI200, 3048c2ecf20Sopenharmony_ci 0, 0, 3058c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_esd200 3068c2ecf20Sopenharmony_ci }, 3078c2ecf20Sopenharmony_ci { 3088c2ecf20Sopenharmony_ci /* esd CAN-CPCI/200 */ 3098c2ecf20Sopenharmony_ci PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, 3108c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_CPCI200, 3118c2ecf20Sopenharmony_ci 0, 0, 3128c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_esd200 3138c2ecf20Sopenharmony_ci }, 3148c2ecf20Sopenharmony_ci { 3158c2ecf20Sopenharmony_ci /* esd CAN-PCI104/200 */ 3168c2ecf20Sopenharmony_ci PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, 3178c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PCI104200, 3188c2ecf20Sopenharmony_ci 0, 0, 3198c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_esd200 3208c2ecf20Sopenharmony_ci }, 3218c2ecf20Sopenharmony_ci { 3228c2ecf20Sopenharmony_ci /* esd CAN-PCI/266 */ 3238c2ecf20Sopenharmony_ci PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056, 3248c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PCI266, 3258c2ecf20Sopenharmony_ci 0, 0, 3268c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_esd266 3278c2ecf20Sopenharmony_ci }, 3288c2ecf20Sopenharmony_ci { 3298c2ecf20Sopenharmony_ci /* esd CAN-PMC/266 */ 3308c2ecf20Sopenharmony_ci PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056, 3318c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PMC266, 3328c2ecf20Sopenharmony_ci 0, 0, 3338c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_esd266 3348c2ecf20Sopenharmony_ci }, 3358c2ecf20Sopenharmony_ci { 3368c2ecf20Sopenharmony_ci /* esd CAN-PCIE/2000 */ 3378c2ecf20Sopenharmony_ci PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056, 3388c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PCIE2000, 3398c2ecf20Sopenharmony_ci 0, 0, 3408c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_esd2000 3418c2ecf20Sopenharmony_ci }, 3428c2ecf20Sopenharmony_ci { 3438c2ecf20Sopenharmony_ci /* IXXAT PC-I 04/PCI card */ 3448c2ecf20Sopenharmony_ci IXXAT_PCI_VENDOR_ID, IXXAT_PCI_DEVICE_ID, 3458c2ecf20Sopenharmony_ci PCI_ANY_ID, IXXAT_PCI_SUB_SYS_ID, 3468c2ecf20Sopenharmony_ci 0, 0, 3478c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_ixxat 3488c2ecf20Sopenharmony_ci }, 3498c2ecf20Sopenharmony_ci { 3508c2ecf20Sopenharmony_ci /* Marathon CAN-bus-PCI card */ 3518c2ecf20Sopenharmony_ci PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID, 3528c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 3538c2ecf20Sopenharmony_ci 0, 0, 3548c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_marathon_pci 3558c2ecf20Sopenharmony_ci }, 3568c2ecf20Sopenharmony_ci { 3578c2ecf20Sopenharmony_ci /* Marathon CAN-bus-PCIe card */ 3588c2ecf20Sopenharmony_ci PCI_VENDOR_ID_PLX, MARATHON_PCIE_DEVICE_ID, 3598c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 3608c2ecf20Sopenharmony_ci 0, 0, 3618c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_marathon_pcie 3628c2ecf20Sopenharmony_ci }, 3638c2ecf20Sopenharmony_ci { 3648c2ecf20Sopenharmony_ci /* TEWS TECHNOLOGIES TPMC810 card */ 3658c2ecf20Sopenharmony_ci TEWS_PCI_VENDOR_ID, TEWS_PCI_DEVICE_ID_TMPC810, 3668c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 3678c2ecf20Sopenharmony_ci 0, 0, 3688c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_tews 3698c2ecf20Sopenharmony_ci }, 3708c2ecf20Sopenharmony_ci { 3718c2ecf20Sopenharmony_ci /* Connect Tech Inc. CANpro/104-Plus Opto (CRG001) card */ 3728c2ecf20Sopenharmony_ci PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, 3738c2ecf20Sopenharmony_ci CTI_PCI_VENDOR_ID, CTI_PCI_DEVICE_ID_CRG001, 3748c2ecf20Sopenharmony_ci 0, 0, 3758c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_cti 3768c2ecf20Sopenharmony_ci }, 3778c2ecf20Sopenharmony_ci { 3788c2ecf20Sopenharmony_ci /* Elcus CAN-200-PCI */ 3798c2ecf20Sopenharmony_ci CAN200PCI_VENDOR_ID, CAN200PCI_DEVICE_ID, 3808c2ecf20Sopenharmony_ci CAN200PCI_SUB_VENDOR_ID, CAN200PCI_SUB_DEVICE_ID, 3818c2ecf20Sopenharmony_ci 0, 0, 3828c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_elcus 3838c2ecf20Sopenharmony_ci }, 3848c2ecf20Sopenharmony_ci { 3858c2ecf20Sopenharmony_ci /* moxa */ 3868c2ecf20Sopenharmony_ci MOXA_PCI_VENDOR_ID, MOXA_PCI_DEVICE_ID, 3878c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 3888c2ecf20Sopenharmony_ci 0, 0, 3898c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_moxa 3908c2ecf20Sopenharmony_ci }, 3918c2ecf20Sopenharmony_ci { 3928c2ecf20Sopenharmony_ci /* ASEM Dual CAN raw */ 3938c2ecf20Sopenharmony_ci ASEM_RAW_CAN_VENDOR_ID, ASEM_RAW_CAN_DEVICE_ID, 3948c2ecf20Sopenharmony_ci ASEM_RAW_CAN_SUB_VENDOR_ID, ASEM_RAW_CAN_SUB_DEVICE_ID, 3958c2ecf20Sopenharmony_ci 0, 0, 3968c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_asem_dual_can 3978c2ecf20Sopenharmony_ci }, 3988c2ecf20Sopenharmony_ci { 3998c2ecf20Sopenharmony_ci /* ASEM Dual CAN raw -new model */ 4008c2ecf20Sopenharmony_ci ASEM_RAW_CAN_VENDOR_ID, ASEM_RAW_CAN_DEVICE_ID, 4018c2ecf20Sopenharmony_ci ASEM_RAW_CAN_SUB_VENDOR_ID, ASEM_RAW_CAN_SUB_DEVICE_ID_BIS, 4028c2ecf20Sopenharmony_ci 0, 0, 4038c2ecf20Sopenharmony_ci (kernel_ulong_t)&plx_pci_card_info_asem_dual_can 4048c2ecf20Sopenharmony_ci }, 4058c2ecf20Sopenharmony_ci { 0,} 4068c2ecf20Sopenharmony_ci}; 4078c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, plx_pci_tbl); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic u8 plx_pci_read_reg(const struct sja1000_priv *priv, int port) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci return ioread8(priv->reg_base + port); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic void plx_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci iowrite8(val, priv->reg_base + port); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/* 4208c2ecf20Sopenharmony_ci * Check if a CAN controller is present at the specified location 4218c2ecf20Sopenharmony_ci * by trying to switch 'em from the Basic mode into the PeliCAN mode. 4228c2ecf20Sopenharmony_ci * Also check states of some registers in reset mode. 4238c2ecf20Sopenharmony_ci */ 4248c2ecf20Sopenharmony_cistatic inline int plx_pci_check_sja1000(const struct sja1000_priv *priv) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci int flag = 0; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* 4298c2ecf20Sopenharmony_ci * Check registers after hardware reset (the Basic mode) 4308c2ecf20Sopenharmony_ci * See states on p. 10 of the Datasheet. 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ci if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) == 4338c2ecf20Sopenharmony_ci REG_CR_BASICCAN_INITIAL && 4348c2ecf20Sopenharmony_ci (priv->read_reg(priv, SJA1000_SR) == REG_SR_BASICCAN_INITIAL) && 4358c2ecf20Sopenharmony_ci (priv->read_reg(priv, SJA1000_IR) == REG_IR_BASICCAN_INITIAL)) 4368c2ecf20Sopenharmony_ci flag = 1; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Bring the SJA1000 into the PeliCAN mode*/ 4398c2ecf20Sopenharmony_ci priv->write_reg(priv, SJA1000_CDR, CDR_PELICAN); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* 4428c2ecf20Sopenharmony_ci * Check registers after reset in the PeliCAN mode. 4438c2ecf20Sopenharmony_ci * See states on p. 23 of the Datasheet. 4448c2ecf20Sopenharmony_ci */ 4458c2ecf20Sopenharmony_ci if (priv->read_reg(priv, SJA1000_MOD) == REG_MOD_PELICAN_INITIAL && 4468c2ecf20Sopenharmony_ci priv->read_reg(priv, SJA1000_SR) == REG_SR_PELICAN_INITIAL && 4478c2ecf20Sopenharmony_ci priv->read_reg(priv, SJA1000_IR) == REG_IR_PELICAN_INITIAL) 4488c2ecf20Sopenharmony_ci return flag; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci/* 4548c2ecf20Sopenharmony_ci * PLX9030/50/52 software reset 4558c2ecf20Sopenharmony_ci * Also LRESET# asserts and brings to reset device on the Local Bus (if wired). 4568c2ecf20Sopenharmony_ci * For most cards it's enough for reset the SJA1000 chips. 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_cistatic void plx_pci_reset_common(struct pci_dev *pdev) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct plx_pci_card *card = pci_get_drvdata(pdev); 4618c2ecf20Sopenharmony_ci u32 cntrl; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci cntrl = ioread32(card->conf_addr + PLX_CNTRL); 4648c2ecf20Sopenharmony_ci cntrl |= PLX_PCI_RESET; 4658c2ecf20Sopenharmony_ci iowrite32(cntrl, card->conf_addr + PLX_CNTRL); 4668c2ecf20Sopenharmony_ci udelay(100); 4678c2ecf20Sopenharmony_ci cntrl ^= PLX_PCI_RESET; 4688c2ecf20Sopenharmony_ci iowrite32(cntrl, card->conf_addr + PLX_CNTRL); 4698c2ecf20Sopenharmony_ci}; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/* 4728c2ecf20Sopenharmony_ci * PLX9056 software reset 4738c2ecf20Sopenharmony_ci * Assert LRESET# and reset device(s) on the Local Bus (if wired). 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_cistatic void plx9056_pci_reset_common(struct pci_dev *pdev) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci struct plx_pci_card *card = pci_get_drvdata(pdev); 4788c2ecf20Sopenharmony_ci u32 cntrl; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* issue a local bus reset */ 4818c2ecf20Sopenharmony_ci cntrl = ioread32(card->conf_addr + PLX9056_CNTRL); 4828c2ecf20Sopenharmony_ci cntrl |= PLX_PCI_RESET; 4838c2ecf20Sopenharmony_ci iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL); 4848c2ecf20Sopenharmony_ci udelay(100); 4858c2ecf20Sopenharmony_ci cntrl ^= PLX_PCI_RESET; 4868c2ecf20Sopenharmony_ci iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* reload local configuration from EEPROM */ 4898c2ecf20Sopenharmony_ci cntrl |= PLX9056_PCI_RCR; 4908c2ecf20Sopenharmony_ci iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* 4938c2ecf20Sopenharmony_ci * There is no safe way to poll for the end 4948c2ecf20Sopenharmony_ci * of reconfiguration process. Waiting for 10ms 4958c2ecf20Sopenharmony_ci * is safe. 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_ci mdelay(10); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci cntrl ^= PLX9056_PCI_RCR; 5008c2ecf20Sopenharmony_ci iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL); 5018c2ecf20Sopenharmony_ci}; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci/* Special reset function for Marathon CAN-bus-PCI card */ 5048c2ecf20Sopenharmony_cistatic void plx_pci_reset_marathon_pci(struct pci_dev *pdev) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci void __iomem *reset_addr; 5078c2ecf20Sopenharmony_ci int i; 5088c2ecf20Sopenharmony_ci static const int reset_bar[2] = {3, 5}; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci plx_pci_reset_common(pdev); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 5138c2ecf20Sopenharmony_ci reset_addr = pci_iomap(pdev, reset_bar[i], 0); 5148c2ecf20Sopenharmony_ci if (!reset_addr) { 5158c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to remap reset " 5168c2ecf20Sopenharmony_ci "space %d (BAR%d)\n", i, reset_bar[i]); 5178c2ecf20Sopenharmony_ci } else { 5188c2ecf20Sopenharmony_ci /* reset the SJA1000 chip */ 5198c2ecf20Sopenharmony_ci iowrite8(0x1, reset_addr); 5208c2ecf20Sopenharmony_ci udelay(100); 5218c2ecf20Sopenharmony_ci pci_iounmap(pdev, reset_addr); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci/* Special reset function for Marathon CAN-bus-PCIe card */ 5278c2ecf20Sopenharmony_cistatic void plx_pci_reset_marathon_pcie(struct pci_dev *pdev) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci void __iomem *addr; 5308c2ecf20Sopenharmony_ci void __iomem *reset_addr; 5318c2ecf20Sopenharmony_ci int i; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci plx9056_pci_reset_common(pdev); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 5368c2ecf20Sopenharmony_ci struct plx_pci_channel_map *chan_map = 5378c2ecf20Sopenharmony_ci &plx_pci_card_info_marathon_pcie.chan_map_tbl[i]; 5388c2ecf20Sopenharmony_ci addr = pci_iomap(pdev, chan_map->bar, chan_map->size); 5398c2ecf20Sopenharmony_ci if (!addr) { 5408c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to remap reset " 5418c2ecf20Sopenharmony_ci "space %d (BAR%d)\n", i, chan_map->bar); 5428c2ecf20Sopenharmony_ci } else { 5438c2ecf20Sopenharmony_ci /* reset the SJA1000 chip */ 5448c2ecf20Sopenharmony_ci #define MARATHON_PCIE_RESET_OFFSET 32 5458c2ecf20Sopenharmony_ci reset_addr = addr + chan_map->offset + 5468c2ecf20Sopenharmony_ci MARATHON_PCIE_RESET_OFFSET; 5478c2ecf20Sopenharmony_ci iowrite8(0x1, reset_addr); 5488c2ecf20Sopenharmony_ci udelay(100); 5498c2ecf20Sopenharmony_ci pci_iounmap(pdev, addr); 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci/* Special reset function for ASEM Dual CAN raw card */ 5558c2ecf20Sopenharmony_cistatic void plx_pci_reset_asem_dual_can_raw(struct pci_dev *pdev) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci void __iomem *bar0_addr; 5588c2ecf20Sopenharmony_ci u8 tmpval; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci plx_pci_reset_common(pdev); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci bar0_addr = pci_iomap(pdev, 0, 0); 5638c2ecf20Sopenharmony_ci if (!bar0_addr) { 5648c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to remap reset space 0 (BAR0)\n"); 5658c2ecf20Sopenharmony_ci return; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* reset the two SJA1000 chips */ 5698c2ecf20Sopenharmony_ci tmpval = ioread8(bar0_addr + ASEM_RAW_CAN_RST_REGISTER); 5708c2ecf20Sopenharmony_ci tmpval &= ~(ASEM_RAW_CAN_RST_MASK_CAN1 | ASEM_RAW_CAN_RST_MASK_CAN2); 5718c2ecf20Sopenharmony_ci iowrite8(tmpval, bar0_addr + ASEM_RAW_CAN_RST_REGISTER); 5728c2ecf20Sopenharmony_ci usleep_range(300, 400); 5738c2ecf20Sopenharmony_ci tmpval |= ASEM_RAW_CAN_RST_MASK_CAN1 | ASEM_RAW_CAN_RST_MASK_CAN2; 5748c2ecf20Sopenharmony_ci iowrite8(tmpval, bar0_addr + ASEM_RAW_CAN_RST_REGISTER); 5758c2ecf20Sopenharmony_ci usleep_range(300, 400); 5768c2ecf20Sopenharmony_ci pci_iounmap(pdev, bar0_addr); 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic void plx_pci_del_card(struct pci_dev *pdev) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct plx_pci_card *card = pci_get_drvdata(pdev); 5828c2ecf20Sopenharmony_ci struct net_device *dev; 5838c2ecf20Sopenharmony_ci struct sja1000_priv *priv; 5848c2ecf20Sopenharmony_ci int i = 0; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci for (i = 0; i < PLX_PCI_MAX_CHAN; i++) { 5878c2ecf20Sopenharmony_ci dev = card->net_dev[i]; 5888c2ecf20Sopenharmony_ci if (!dev) 5898c2ecf20Sopenharmony_ci continue; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Removing %s\n", dev->name); 5928c2ecf20Sopenharmony_ci unregister_sja1000dev(dev); 5938c2ecf20Sopenharmony_ci priv = netdev_priv(dev); 5948c2ecf20Sopenharmony_ci if (priv->reg_base) 5958c2ecf20Sopenharmony_ci pci_iounmap(pdev, priv->reg_base); 5968c2ecf20Sopenharmony_ci free_sja1000dev(dev); 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci card->reset_func(pdev); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* 6028c2ecf20Sopenharmony_ci * Disable interrupts from PCI-card and disable local 6038c2ecf20Sopenharmony_ci * interrupts 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ci if (pdev->device != PCI_DEVICE_ID_PLX_9056 && 6068c2ecf20Sopenharmony_ci pdev->device != MARATHON_PCIE_DEVICE_ID) 6078c2ecf20Sopenharmony_ci iowrite32(0x0, card->conf_addr + PLX_INTCSR); 6088c2ecf20Sopenharmony_ci else 6098c2ecf20Sopenharmony_ci iowrite32(0x0, card->conf_addr + PLX9056_INTCSR); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (card->conf_addr) 6128c2ecf20Sopenharmony_ci pci_iounmap(pdev, card->conf_addr); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci kfree(card); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci pci_disable_device(pdev); 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci/* 6208c2ecf20Sopenharmony_ci * Probe PLX90xx based device for the SJA1000 chips and register each 6218c2ecf20Sopenharmony_ci * available CAN channel to SJA1000 Socket-CAN subsystem. 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_cistatic int plx_pci_add_card(struct pci_dev *pdev, 6248c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct sja1000_priv *priv; 6278c2ecf20Sopenharmony_ci struct net_device *dev; 6288c2ecf20Sopenharmony_ci struct plx_pci_card *card; 6298c2ecf20Sopenharmony_ci struct plx_pci_card_info *ci; 6308c2ecf20Sopenharmony_ci int err, i; 6318c2ecf20Sopenharmony_ci u32 val; 6328c2ecf20Sopenharmony_ci void __iomem *addr; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci ci = (struct plx_pci_card_info *)ent->driver_data; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (pci_enable_device(pdev) < 0) { 6378c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to enable PCI device\n"); 6388c2ecf20Sopenharmony_ci return -ENODEV; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Detected \"%s\" card at slot #%i\n", 6428c2ecf20Sopenharmony_ci ci->name, PCI_SLOT(pdev->devfn)); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* Allocate card structures to hold addresses, ... */ 6458c2ecf20Sopenharmony_ci card = kzalloc(sizeof(*card), GFP_KERNEL); 6468c2ecf20Sopenharmony_ci if (!card) { 6478c2ecf20Sopenharmony_ci pci_disable_device(pdev); 6488c2ecf20Sopenharmony_ci return -ENOMEM; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, card); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci card->channels = 0; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* Remap PLX90xx configuration space */ 6568c2ecf20Sopenharmony_ci addr = pci_iomap(pdev, ci->conf_map.bar, ci->conf_map.size); 6578c2ecf20Sopenharmony_ci if (!addr) { 6588c2ecf20Sopenharmony_ci err = -ENOMEM; 6598c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to remap configuration space " 6608c2ecf20Sopenharmony_ci "(BAR%d)\n", ci->conf_map.bar); 6618c2ecf20Sopenharmony_ci goto failure_cleanup; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci card->conf_addr = addr + ci->conf_map.offset; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci ci->reset_func(pdev); 6668c2ecf20Sopenharmony_ci card->reset_func = ci->reset_func; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* Detect available channels */ 6698c2ecf20Sopenharmony_ci for (i = 0; i < ci->channel_count; i++) { 6708c2ecf20Sopenharmony_ci struct plx_pci_channel_map *cm = &ci->chan_map_tbl[i]; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci dev = alloc_sja1000dev(0); 6738c2ecf20Sopenharmony_ci if (!dev) { 6748c2ecf20Sopenharmony_ci err = -ENOMEM; 6758c2ecf20Sopenharmony_ci goto failure_cleanup; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci card->net_dev[i] = dev; 6798c2ecf20Sopenharmony_ci priv = netdev_priv(dev); 6808c2ecf20Sopenharmony_ci priv->priv = card; 6818c2ecf20Sopenharmony_ci priv->irq_flags = IRQF_SHARED; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci dev->irq = pdev->irq; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* 6868c2ecf20Sopenharmony_ci * Remap IO space of the SJA1000 chips 6878c2ecf20Sopenharmony_ci * This is device-dependent mapping 6888c2ecf20Sopenharmony_ci */ 6898c2ecf20Sopenharmony_ci addr = pci_iomap(pdev, cm->bar, cm->size); 6908c2ecf20Sopenharmony_ci if (!addr) { 6918c2ecf20Sopenharmony_ci err = -ENOMEM; 6928c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to remap BAR%d\n", cm->bar); 6938c2ecf20Sopenharmony_ci goto failure_cleanup; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci priv->reg_base = addr + cm->offset; 6978c2ecf20Sopenharmony_ci priv->read_reg = plx_pci_read_reg; 6988c2ecf20Sopenharmony_ci priv->write_reg = plx_pci_write_reg; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* Check if channel is present */ 7018c2ecf20Sopenharmony_ci if (plx_pci_check_sja1000(priv)) { 7028c2ecf20Sopenharmony_ci priv->can.clock.freq = ci->can_clock; 7038c2ecf20Sopenharmony_ci priv->ocr = ci->ocr; 7048c2ecf20Sopenharmony_ci priv->cdr = ci->cdr; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 7078c2ecf20Sopenharmony_ci dev->dev_id = i; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* Register SJA1000 device */ 7108c2ecf20Sopenharmony_ci err = register_sja1000dev(dev); 7118c2ecf20Sopenharmony_ci if (err) { 7128c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Registering device failed " 7138c2ecf20Sopenharmony_ci "(err=%d)\n", err); 7148c2ecf20Sopenharmony_ci goto failure_cleanup; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci card->channels++; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d " 7208c2ecf20Sopenharmony_ci "registered as %s\n", i + 1, priv->reg_base, 7218c2ecf20Sopenharmony_ci dev->irq, dev->name); 7228c2ecf20Sopenharmony_ci } else { 7238c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Channel #%d not detected\n", 7248c2ecf20Sopenharmony_ci i + 1); 7258c2ecf20Sopenharmony_ci free_sja1000dev(dev); 7268c2ecf20Sopenharmony_ci card->net_dev[i] = NULL; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (!card->channels) { 7318c2ecf20Sopenharmony_ci err = -ENODEV; 7328c2ecf20Sopenharmony_ci goto failure_cleanup; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* 7368c2ecf20Sopenharmony_ci * Enable interrupts from PCI-card (PLX90xx) and enable Local_1, 7378c2ecf20Sopenharmony_ci * Local_2 interrupts from the SJA1000 chips 7388c2ecf20Sopenharmony_ci */ 7398c2ecf20Sopenharmony_ci if (pdev->device != PCI_DEVICE_ID_PLX_9056 && 7408c2ecf20Sopenharmony_ci pdev->device != MARATHON_PCIE_DEVICE_ID) { 7418c2ecf20Sopenharmony_ci val = ioread32(card->conf_addr + PLX_INTCSR); 7428c2ecf20Sopenharmony_ci if (pdev->subsystem_vendor == PCI_VENDOR_ID_ESDGMBH) 7438c2ecf20Sopenharmony_ci val |= PLX_LINT1_EN | PLX_PCI_INT_EN; 7448c2ecf20Sopenharmony_ci else 7458c2ecf20Sopenharmony_ci val |= PLX_LINT1_EN | PLX_LINT2_EN | PLX_PCI_INT_EN; 7468c2ecf20Sopenharmony_ci iowrite32(val, card->conf_addr + PLX_INTCSR); 7478c2ecf20Sopenharmony_ci } else { 7488c2ecf20Sopenharmony_ci iowrite32(PLX9056_LINTI | PLX9056_PCI_INT_EN, 7498c2ecf20Sopenharmony_ci card->conf_addr + PLX9056_INTCSR); 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci return 0; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cifailure_cleanup: 7548c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci plx_pci_del_card(pdev); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci return err; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cistatic struct pci_driver plx_pci_driver = { 7628c2ecf20Sopenharmony_ci .name = DRV_NAME, 7638c2ecf20Sopenharmony_ci .id_table = plx_pci_tbl, 7648c2ecf20Sopenharmony_ci .probe = plx_pci_add_card, 7658c2ecf20Sopenharmony_ci .remove = plx_pci_del_card, 7668c2ecf20Sopenharmony_ci}; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cimodule_pci_driver(plx_pci_driver); 769