From b99e666b3b0b03c12fc30f4ad6fec9caa6e1a13d Mon Sep 17 00:00:00 2001 From: ppisa Date: Fri, 18 Jun 2004 01:45:23 +0000 Subject: [PATCH 1/1] EMS CPC-PCI card support finished. Requires testing, some bugs and mistakes are very probable, because I have no access to the hardware.. --- lincan/src/ems_cpcpci.c | 154 ++++++++++++++++++++++++++++++---------- 1 file changed, 117 insertions(+), 37 deletions(-) diff --git a/lincan/src/ems_cpcpci.c b/lincan/src/ems_cpcpci.c index 0fa2897..63cf430 100644 --- a/lincan/src/ems_cpcpci.c +++ b/lincan/src/ems_cpcpci.c @@ -18,7 +18,7 @@ # define EMS_CPCPCI_PCICAN_VENDOR 0x110a # define EMS_CPCPCI_PCICAN_ID 0x2104 -/*The PSB4610 is used as PCI to local bus bridge*/ +/*The Infineon PSB4610 PITA-2 is used as PCI to local bus bridge*/ /*BAR0 - MEM - bridge control registers*/ /*BAR1 - MEM - parallel interface*/ @@ -28,16 +28,14 @@ * each register occupies 4 bytes */ -/*AMCC 5920*/ -#define S5920_OMB 0x0C -#define S5920_IMB 0x1C -#define S5920_MBEF 0x34 -#define S5920_INTCSR 0x38 -#define S5920_RCR 0x3C -#define S5920_PTCR 0x60 +/*PSB4610 PITA-2 bridge control registers*/ +#define PITA2_ICR 0x00 /* Interrupt Control Register */ +#define PITA2_ICR_INT0 0x00000002 /* [RC] INT0 Active/Clear */ +#define PITA2_ICR_INT0_En 0x00020000 /* [RW] Enable INT0 */ -#define INTCSR_ADDON_INTENABLE_M 0x2000 -#define INTCSR_INTERRUPT_ASSERTED_M 0x800000 +#define PITA2_MISC 0x1C /* Miscellaneous Register */ +#define PITA2_MISC_CONFIG 0x04000000 + /* Multiplexed Parallel_interface_mode */ #define EMS_CPCPCI_BYTES_PER_CIRCUIT 0x200 /* Each CPC register occupies 4 bytes */ @@ -50,15 +48,16 @@ /* -You need to know the following: +The board configuration is probably following: " RX1 is connected to ground. " TX1 is not connected. " CLKO is not connected. " Setting the OCR register to 0xDA is a good idea. This means normal output mode , push-pull and the correct polarity. " In the CDR register, you should set CBP to 1. - You will probably also want to set the clock divider value to 0 (meaning divide-by-2), - the Pelican bit, and the clock-off bit (you have no need for CLKOUT anyway.) + You will probably also want to set the clock divider value to 7 + (meaning direct oscillator output) because the second SJA1000 chip + is driven by the first one CLKOUT output. */ @@ -66,35 +65,30 @@ You need to know the following: void ems_cpcpci_disconnect_irq(struct candevice_t *candev) { - unsigned long tmp; /* Disable interrupts from card */ - tmp = inl(candev->dev_base_addr + S5920_INTCSR); - tmp &= ~INTCSR_ADDON_INTENABLE_M; - outl(tmp, candev->dev_base_addr + S5920_INTCSR); + writel(0, candev->dev_base_addr + PITA2_ICR); } void ems_cpcpci_connect_irq(struct candevice_t *candev) { - unsigned long tmp; /* Enable interrupts from card */ - tmp = inl(candev->dev_base_addr + S5920_INTCSR); - tmp |= INTCSR_ADDON_INTENABLE_M; - outl(tmp, candev->dev_base_addr + S5920_INTCSR); + writel(PITA2_ICR_INT0_En, candev->dev_base_addr + PITA2_ICR); } int ems_cpcpci_request_io(struct candevice_t *candev) { + unsigned long pita2_addr; + unsigned long io_addr; + int i; + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) - if(pci_request_region(candev->sysdevptr.pcidev, 0, "ems_cpcpci_s5920") != 0){ - CANMSG("Request of ems_cpcpci_s5920 range failed\n"); + if(pci_request_region(candev->sysdevptr.pcidev, 0, "ems_cpcpci_pita2") != 0){ + CANMSG("Request of ems_cpcpci_pita2 range failed\n"); return -ENODEV; }else if(pci_request_region(candev->sysdevptr.pcidev, 1, "ems_cpcpci_io") != 0){ CANMSG("Request of ems_cpcpci_io range failed\n"); goto error_io; - }else if(pci_request_region(candev->sysdevptr.pcidev, 2, "ems_cpcpci_xilinx") != 0){ - CANMSG("Request of ems_cpcpci_xilinx range failed\n"); - goto error_xilinx; } #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ if(pci_request_regions(candev->sysdevptr.pcidev, "EMS_CPCPCI") != 0){ @@ -103,15 +97,51 @@ int ems_cpcpci_request_io(struct candevice_t *candev) } #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + pita2_addr=pci_resource_start(candev->sysdevptr.pcidev,0); + if (!(candev->dev_base_addr = (long) ioremap(pita2_addr, + pci_resource_len(candev->sysdevptr.pcidev,0)))) { + CANMSG("Unable to access I/O memory at: 0x%lx\n", pita2_addr); + goto error_ioremap_pita2; + } + + io_addr=pci_resource_start(candev->sysdevptr.pcidev,1);; + if (!(candev->io_addr = (long) ioremap(io_addr, + pci_resource_len(candev->sysdevptr.pcidev,1)))) { + CANMSG("Unable to access I/O memory at: 0x%lx\n", io_addr); + goto error_ioremap_io; + } + + candev->res_addr=candev->io_addr; + + /* + * this is redundant with chip initialization, but remap address + * can change when resources are temporarily released + */ + for(i=0;inr_all_chips;i++) { + struct chip_t *chip=candev->chip[i]; + if(!chip) continue; + chip->chip_base_addr = candev->io_addr+ + 0x400 + i*EMS_CPCPCI_BYTES_PER_CIRCUIT; + if(!chip->msgobj[0]) continue; + chip->msgobj[0]->obj_base_addr=chip->chip_base_addr; + } + + /* Configure PITA-2 parallel interface */ + writel(PITA2_MISC_CONFIG, candev->dev_base_addr + PITA2_MISC); + ems_cpcpci_disconnect_irq(candev); return 0; + error_ioremap_io: + iounmap((void*)candev->dev_base_addr); + error_ioremap_pita2: #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) - error_xilinx: pci_release_region(candev->sysdevptr.pcidev, 1); error_io: pci_release_region(candev->sysdevptr.pcidev, 0); + #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ + pci_release_regions(candev->sysdevptr.pcidev); #endif /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ return -ENODEV; @@ -121,8 +151,9 @@ int ems_cpcpci_release_io(struct candevice_t *candev) { ems_cpcpci_disconnect_irq(candev); + iounmap((void*)candev->io_addr); + iounmap((void*)candev->dev_base_addr); #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21)) - pci_release_region(candev->sysdevptr.pcidev, 2); pci_release_region(candev->sysdevptr.pcidev, 1); pci_release_region(candev->sysdevptr.pcidev, 0); #else /*(LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21))*/ @@ -147,6 +178,32 @@ unsigned ems_cpcpci_read_register(unsigned long address) return readb(address); } +extern can_irqreturn_t sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs); + +can_irqreturn_t ems_cpcpci_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct chip_t *chip=(struct chip_t *)dev_id; + struct candevice_t *candev=chip->hostdevice; + int i; + unsigned long icr; + + icr=readl(candev->dev_base_addr + PITA2_ICR); + if(!(icr & PITA2_ICR_INT0)) return IRQ_NONE; + + /* correct way to handle interrupts from all chips connected to the one PITA-2 */ + do { + writel(PITA2_ICR_INT0_En | PITA2_ICR_INT0, candev->dev_base_addr + PITA2_ICR); + for(i=0;inr_all_chips;i++){ + chip=candev->chip[i]; + if(!chip || !(chip->flags&CHIP_CONFIGURED)) + continue; + sja1000p_irq_handler(irq, dev_id, regs); + } + icr=readl(candev->dev_base_addr + PITA2_ICR); + } while(icr & PITA2_ICR_INT0); + return IRQ_HANDLED; +} + int ems_cpcpci_reset(struct candevice_t *candev) { int i=0,chip_nr; @@ -156,7 +213,6 @@ int ems_cpcpci_reset(struct candevice_t *candev) DEBUGMSG("Resetting EMS_CPCPCI hardware ...\n"); /* Assert PTADR# - we're in passive mode so the other bits are not important */ - outl(0x80808080L, candev->dev_base_addr + S5920_PTCR); ems_cpcpci_disconnect_irq(candev); @@ -198,6 +254,7 @@ int ems_cpcpci_init_hw_data(struct candevice_t *candev) { struct pci_dev *pcidev = NULL; int i; + unsigned long l; pcidev = pci_find_device(EMS_CPCPCI_PCICAN_VENDOR, EMS_CPCPCI_PCICAN_ID, pcidev); if(pcidev == NULL) return -ENODEV; @@ -214,6 +271,11 @@ int ems_cpcpci_init_hw_data(struct candevice_t *candev) return -EIO; } } + + /*request IO access temporarily to check card presence*/ + if(ems_cpcpci_request_io(candev)<0) + return -ENODEV; + candev->dev_base_addr=pci_resource_start(pcidev,0); /*S5920*/ /* some control registers */ candev->io_addr=pci_resource_start(pcidev,1); @@ -224,12 +286,25 @@ int ems_cpcpci_init_hw_data(struct candevice_t *candev) */ /*candev->flags |= CANDEV_PROGRAMMABLE_IRQ;*/ - - if (!strcmp(candev->hwname,"ems_cpcpci")) { - candev->nr_82527_chips=0; - candev->nr_sja1000_chips=2; - candev->nr_all_chips=2; + + for(l=0,i=0;i<4;i++){ + l<<=8; + l|=readb(candev->io_addr + i*4); } + i=readb(candev->io_addr + i*5); + + CANMSG("EMS CPC-PCI check value %04lx, ID %d\n", l, i); + + if((l!=0x55aa01cb)||(i!=0x11)) { + CANMSG("EMS CPC-PCI unexpected check values\n"); + } + + /*if (!strcmp(candev->hwname,"ems_cpcpci"))*/ + candev->nr_82527_chips=0; + candev->nr_sja1000_chips=2; + candev->nr_all_chips=2; + + ems_cpcpci_release_io(candev); return 0; } @@ -238,8 +313,12 @@ int ems_cpcpci_init_chip_data(struct candevice_t *candev, int chipnr) { if(candev->sysdevptr.pcidev==NULL) return -ENODEV; - + + /* initialize common routines for the SJA1000 chip */ sja1000p_fill_chipspecops(candev->chip[chipnr]); + + /* special version of the IRQ handler is required for CPC-PCI board */ + candev->chip[chipnr]->chipspecops->irq_handler=ems_cpcpci_irq_handler; candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq; @@ -249,9 +328,10 @@ int ems_cpcpci_init_chip_data(struct candevice_t *candev, int chipnr) candev->chip[chipnr]->int_cpu_reg = 0; candev->chip[chipnr]->int_clk_reg = 0; candev->chip[chipnr]->int_bus_reg = 0; - candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF; + /* CLKOUT has to be equal to oscillator frequency to drive second chip */ + candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | 7; candev->chip[chipnr]->sja_ocr_reg = EMS_CPCPCI_OCR_DEFAULT_STD; - candev->chip[chipnr]->clock = 8000000; + candev->chip[chipnr]->clock = 16000000; candev->chip[chipnr]->flags |= CHIP_IRQ_PCI; return 0; -- 2.39.2