NOTICE: The Processors Wiki will End-of-Life on January 15, 2021. It is recommended to download any files or other content you may need that are hosted on processors.wiki.ti.com. The site is now set to read only.
Test PCI Driver
Contents
Introduction[edit]
This document describes the PCI test driver, which can be used to test the PCI hardware before running DSPLink.
Overview[edit]
This PCI driver tests all hardware related aspect needed by DSPLink for providing support on the desired platform. DSPLink requires memory to be shared between HOST and device, power management, interrupts between HOST and device and EDMA features of DSP device. This test driver tests each of these components.
Details[edit]
This test driver is written from the DSP and HAL logic of DSPLink source. APIs provided by this test driver are somewhat similar to
APIs provided by DSPLink DSP and HAL code.
It gives out error message incase of failure otherwise it prints successful message.
#include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/ioport.h> #include <linux/interrupt.h> #include <asm/uaccess.h> /** ============================================================================ * @macro Data types * * @desc Basic data types * ============================================================================ */ typedef signed char Int8 ; /* 8 bit value */ typedef signed short int Int16 ; /* 16 bit value */ typedef signed long int Int32 ; /* 32 bit value */ typedef unsigned char Uint8 ; /* 8 bit value */ typedef unsigned short int Uint16 ; /* 16 bit value */ typedef unsigned long int Uint32 ; /* 32 bit value */ typedef float Real32 ; /* 32 bit value */ typedef double Real64 ; /* 64 bit value */ typedef short int Bool ; /* 16 bit value */ typedef char Char8 ; /* 8 bit value */ typedef short Char16 ; /* 16 bit value */ typedef unsigned char Uchar8 ; /* 8 bit value */ typedef unsigned short Uchar16 ; /* 16 bit value */ #define Void void typedef void * Pvoid ; typedef Char8 * Pstr ; typedef Uchar8 * Pustr ; /** ============================================================================ * @const PCI_TI_VENDOR * * @desc TI Vendor ID. * ============================================================================ */ #define PCI_TI_VENDOR 0x104c /** ============================================================================ * @const PCI_TI_DEVICE * * @desc PCI Device ID. * ============================================================================ */ #define PCI_TI_DEVICE 0xB001 /** ============================================================================ * @const DM64LCPCI_DEVREG_BASE * * @desc Base address of Device config registers. * ============================================================================ */ #define DM64LCPCI_DEVREG_BASE 0x01C40000 /** ============================================================================ * @const DM64LCPCI_PLLREG_BASE * * @desc Base address of PLL0 registers. * ============================================================================ */ #define DM64LCPCI_PLL0REG_BASE 0x01C40800 /** ============================================================================ * @const DM64LCPCI_PLLREG_BASE * * @desc Base address of PLL1 registers. * ============================================================================ */ #define DM64LCPCI_PLL1REG_BASE 0x01C40C00 /** ============================================================================ * @const DM64LCPCI_EDMAREG_BASE * * @desc Base address of EDMA registers. * ============================================================================ */ #define DM64LCPCI_EDMAREG_BASE 0x01C00000 /** ============================================================================ * @const DM64LCPCI_DDRREG_BASE * * @desc Base address of DDR PHY registers. * ============================================================================ */ #define DM64LCPCI_DDRREG_BASE 0x20000000 /** ============================================================================ * @const DM64LCPCI_PSCREG_BASE * * @desc Base address of PSC registers. * ============================================================================ */ #define DM64LCPCI_PSCREG_BASE 0x01C41000 /** ============================================================================ * @const DM64LCPCI_PCIREG_BASE * * @desc Base address of PCI backend registers. * ============================================================================ */ #define DM64LCPCI_PCIREG_BASE 0x01C1A000 /** ============================================================================ * @const DM64LCPCI_SOFTINT0_MASK * * @desc Mask for generating soft int0 (DSP->GPP) * ============================================================================ */ #define DM64LCPCI_SOFTINT0_MASK 0x01000000 /** ============================================================================ * @const DM64LCPCI_SOFTINT1_MASK * * @desc Mask for generating soft int1 (GPP->DSP) * ============================================================================ */ #define DM64LCPCI_SOFTINT1_MASK 0x02000000 /** ============================================================================ * @const DM64LCPCI_LRESET_MASK * * @desc Mask for reseting/releasing GEM. * ============================================================================ */ #define DM64LCPCI_LRESET_MASK 0x00000100 /** ============================================================================ * @const DM64LCPCI_INTSTATUS_MASK * * @desc Bitmask for Interrupt status (DSP->GPP) * ============================================================================ */ #define DM64LCPCI_INTSTATUS_MASK 0x00080000 /** ============================================================================ * @const DM64LCPCI_PCIADLEN * * @desc Length each segment of addressable PCI Space.. * ============================================================================ */ #define DM64LCPCI_PCIADLEN 0x00800000 /** ============================================================================ * @const DM64LCPCI_PCIADWRBITMASK * * @desc Mask indicating writeable bits in PCI Address Window registers. * ============================================================================ */ #define DM64LCPCI_PCIADWRBITMASK 0xFF800000 /** ============================================================================ * @const DM64LCPCI_PAGEWRBITMASK * * @desc Mask indicating writeable bits in PCI Base Address Mask Register5. * ============================================================================ */ #define DM64LCPCI_PAGEWRBITMASK 0xFF800000 /** ============================================================================ * @name DM64LCPCI_pllRegs * * @desc Register Overlay Structure for Device config registers. * ============================================================================ */ typedef struct DM64LCPCI_devRegs_tag { volatile Uint32 PINMUX0 ; volatile Uint32 PINMUX1 ; volatile Uint32 DSPBOOTADDR ; volatile Uint32 BOOTCMPLT ; volatile Uint32 RSVD0 ; volatile Uint32 BOOTCFG ; volatile Uint32 VDD1P0V_ADJ ; volatile Uint32 VDD1P2V_ADJ ; volatile Uint32 DDR_SLEW ; volatile Uint32 PERIPHEN ; volatile Uint32 DEVICE_ID ; volatile Uint32 DAC_DEMEN ; volatile Uint32 UHPICTL ; volatile Uint32 RSVD1 [2] ; volatile Uint32 MSTPRI0 ; volatile Uint32 MSTPRI1 ; volatile Uint32 VPSS_CLK_CTRL ; volatile Uint32 VDD3P3V_PWRDN ; volatile Uint32 DFT_ENABLE ; volatile Uint32 SEC_SCAN_REG ; volatile Uint32 SEC_TEST_REG ; volatile Uint32 SEC_TAP_CTL ; volatile Uint32 PUBLIC_KEY0 ; volatile Uint32 PUBLIC_KEY1 ; volatile Uint32 PUBLIC_KEY2 ; volatile Uint32 PUBLIC_KEY3 ; volatile Uint32 VLYNQ_DELAY ; volatile Uint32 SEC_PSEUDO0 ; volatile Uint32 SEC_PSEUDO1 ; volatile Uint32 RSVD2 [3] ; volatile Uint32 TIMERCTL ; volatile Uint32 TPTCCCFG ; volatile Uint32 RSVD3 ; } DM64LCPCI_devRegs ; /** ============================================================================ * @name DM64LCPCI_pllRegs * * @desc Register Overlay Structure for PLL. * ============================================================================ */ typedef struct DM64LCPCI_pllRegs_tag { volatile Uint32 PID ; volatile Uint8 RSVD0 [220] ; volatile Uint32 FUSERR ; volatile Uint32 RSTYPE ; volatile Uint32 RSTDEF ; volatile Uint8 RSVD1 [20] ; volatile Uint32 PLLCTL ; volatile Uint32 OCSEL ; volatile Uint32 SECCTL ; volatile Uint8 RSVD2 [4] ; volatile Uint32 PLLM ; volatile Uint32 PREDIV ; volatile Uint32 PLLDIV1 ; volatile Uint32 PLLDIV2 ; volatile Uint32 PLLDIV3 ; volatile Uint32 OSCDIV1 ; volatile Uint32 POSTDIV ; volatile Uint32 BPDIV ; volatile Uint32 WAKEUP ; volatile Uint8 RSVD3 [4] ; volatile Uint32 PLLCMD ; volatile Uint32 PLLSTAT ; volatile Uint32 ALNCTL ; volatile Uint32 DCHANGE ; volatile Uint32 CKEN ; volatile Uint32 CKSTAT ; volatile Uint32 SYSTAT ; volatile Uint8 RSVD4 [12] ; volatile Uint32 PLLDIV4 ; volatile Uint32 PLLDIV5 ; volatile Uint32 PLLDIV6 ; volatile Uint32 PLLDIV7 ; volatile Uint32 PLLDIV8 ; } DM64LCPCI_pllRegs ; /** ============================================================================ * @name DM64LCPCI_ddrRegs * * @desc Register Overlay Structure for DDR. * ============================================================================ */ typedef struct { volatile Uint32 ERCSR ; volatile Uint32 SDRSTAT ; volatile Uint32 SDBCR ; volatile Uint32 SDRCR ; volatile Uint32 SDTIMR ; volatile Uint32 SDTIMR2 ; volatile Uint8 RSVD0 [8] ; volatile Uint32 VBPR ; volatile Uint8 RSVD1 [4] ; volatile Uint32 VBCFG1 ; volatile Uint32 VBCFG2 ; volatile Uint8 RSVD2 [16] ; volatile Uint32 PERFC1R ; volatile Uint32 PERFC2R ; volatile Uint32 PCCR ; volatile Uint32 PCMRSR ; volatile Uint8 RSVD3 [48] ; volatile Uint32 ASYNCCS2CR ; volatile Uint32 ASYNCCS3CR ; volatile Uint32 ASYNCCS4CR ; volatile Uint32 ASYNCCS5CR ; volatile Uint8 RSVD4 [16] ; volatile Uint32 AWCCR ; volatile Uint8 RSVD5 [28] ; volatile Uint32 IRR ; volatile Uint32 IMR ; volatile Uint32 IMSR ; volatile Uint32 IMCR ; volatile Uint8 RSVD6 [16] ; volatile Uint32 DDRPHYREV ; volatile Uint32 DDRPHYCR ; volatile Uint32 DDRPHYSR ; volatile Uint8 RSVD7 [4] ; volatile Uint32 VTPCTRL ; volatile Uint32 VTPSTAT ; } DM64LCPCI_ddrRegs ; /** ============================================================================ * @name DM64LCPCI_pscRegs * * @desc Register Overlay Structure for PSC. * ============================================================================ */ typedef struct DM64LCPCI_pscRegs_tag { volatile Uint32 PID ; volatile Uint8 RSVD0 [12] ; volatile Uint32 GBLCTL ; volatile Uint8 RSVD1 [4] ; volatile Uint32 INTEVAL ; volatile Uint8 RSVD2 [36] ; volatile Uint32 ERRPR0 ; volatile Uint32 ERRPR1 ; volatile Uint8 RSVD3 [8] ; volatile Uint32 ERRCR0 ; volatile Uint32 ERRCR1 ; volatile Uint8 RSVD4 [8] ; volatile Uint32 PERRPR ; volatile Uint8 RSVD5 [4] ; volatile Uint32 PERRCR ; volatile Uint8 RSVD6 [4] ; volatile Uint32 EPCPR ; volatile Uint8 RSVD7 [4] ; volatile Uint32 EPCR ; volatile Uint8 RSVD8 [132] ; volatile Uint32 RAILSTAT ; volatile Uint32 RAILCTL ; volatile Uint32 RAILSEL ; volatile Uint8 RSVD9 [20] ; volatile Uint32 PTCMD ; volatile Uint8 RSVD10 [4] ; volatile Uint32 PTSTAT ; volatile Uint8 RSVD11 [212] ; volatile Uint32 PDSTAT [41] ; volatile Uint8 RSVD12 [92] ; volatile Uint32 PDCTL [41] ; volatile Uint8 RSVD13 [348] ; volatile Uint32 MRSTOUT [2] ; volatile Uint8 RSVD14 [8] ; volatile Uint32 MCKOUT [2] ; volatile Uint8 RSVD15 [232] ; volatile Uint32 MDCFG [41] ; volatile Uint8 RSVD16 [348] ; volatile Uint32 MDSTAT [41] ; volatile Uint8 RSVD17 [348] ; volatile Uint32 MDCTL [41] ; } DM64LCPCI_pscRegs ; /** ============================================================================ * @name DM64LCPCI_paramEntry * * @desc Register Overlay Structure for PARAMENTRY. * ============================================================================ */ typedef struct DM64LCPCI_paramEntry_tags { volatile Uint32 OPTION ; volatile Uint32 SRC ; volatile Uint32 A_B_CNT ; volatile Uint32 DST ; volatile Uint32 SRC_DST_BIDX ; volatile Uint32 LINK_BCNTRLD ; volatile Uint32 SRC_DST_CIDX ; volatile Uint32 CCNT ; } DM64LCPCI_paramEntry ; /** ============================================================================ * @name DM64LCPCI_edmaRegs * * @desc Register Overlay Structure for EDMA. * ============================================================================ */ typedef struct DM64LCPCI_edmaRegs_tag { volatile Uint32 REV ; volatile Uint32 CCCFG ; volatile Uint8 RSVD0 [248] ; volatile Uint32 DCHMAP [64] ; volatile Uint32 QCHMAP [8] ; volatile Uint8 RSVD1 [32] ; volatile Uint32 DMAQNUM [8] ; volatile Uint32 QDMAQNUM ; volatile Uint8 RSVD2 [28] ; volatile Uint32 QUETCMAP ; volatile Uint32 QUEPRI ; volatile Uint8 RSVD3 [120] ; volatile Uint32 EMR ; volatile Uint32 EMRH ; volatile Uint32 EMCR ; volatile Uint32 EMCRH ; volatile Uint32 QEMR ; volatile Uint32 QEMCR ; volatile Uint32 CCERR ; volatile Uint32 CCERRCLR ; volatile Uint32 EEVAL ; volatile Uint8 RSVD4 [28] ; volatile Uint8 RSVD5 [64] ; volatile Uint32 QRAE [8] ; volatile Uint8 RSVD6[96] ; volatile Uint8 RSVD7 [512] ; volatile Uint32 QSTAT [8] ; volatile Uint32 QWMTHRA ; volatile Uint32 QWMTHRB ; volatile Uint8 RSVD8 [24] ; volatile Uint32 CCSTAT ; volatile Uint8 RSVD9 [188] ; volatile Uint32 AETCTL ; volatile Uint32 AETSTAT ; volatile Uint32 AETCMD ; volatile Uint8 RSVD10 [244] ; volatile Uint32 MPFAR ; volatile Uint32 MPFSR ; volatile Uint32 MPFCR ; volatile Uint32 MPPAG ; volatile Uint32 MPPA [8] ; volatile Uint8 RSVD11 [2000] ; volatile Uint32 ER ; volatile Uint32 ERH ; volatile Uint32 ECR ; volatile Uint32 ECRH ; volatile Uint32 ESR ; volatile Uint32 ESRH ; volatile Uint32 CER ; volatile Uint32 CERH ; volatile Uint32 EER ; volatile Uint32 EERH ; volatile Uint32 EECR ; volatile Uint32 EECRH ; volatile Uint32 EESR ; volatile Uint32 EESRH ; volatile Uint32 SER ; volatile Uint32 SERH ; volatile Uint32 SECR ; volatile Uint32 SECRH ; volatile Uint8 RSVD12 [8] ; volatile Uint32 IER ; volatile Uint32 IERH ; volatile Uint32 IECR ; volatile Uint32 IECRH ; volatile Uint32 IESR ; volatile Uint32 IESRH ; volatile Uint32 IPR ; volatile Uint32 IPRH ; volatile Uint32 ICR ; volatile Uint32 ICRH ; volatile Uint32 IEVAL ; volatile Uint8 RSVD13 [4] ; volatile Uint32 QER ; volatile Uint32 QEER ; volatile Uint32 QEECR ; volatile Uint32 QEESR ; volatile Uint32 QSER ; volatile Uint32 QSECR ; volatile Uint8 RSVD14 [3944] ; volatile Uint8 RSVD15 [4096] ; volatile Uint8 RSVD16 [4096] ; DM64LCPCI_paramEntry PARAMENTRY[512] ; } DM64LCPCI_edmaRegs ; /** ============================================================================ * @name DM64LCPCI_pciRegs * * @desc PCI Back end register overlay structure. * ============================================================================ */ typedef struct DM64LCPCI_pciRegs_tag { volatile Uint32 PCIREVID ; volatile Uint8 RSVD0 [12] ; volatile Uint32 PCISTATSET ; volatile Uint32 PCISTATCLR ; volatile Uint8 RSVD1 [8] ; volatile Uint32 PCIHINTSET ; volatile Uint32 PCIHINTCLR ; volatile Uint8 RSVD2 [8] ; volatile Uint32 PCIBINTSET ; volatile Uint32 PCIBINTCLR ; volatile Uint32 PCIBCLKMGT ; volatile Uint8 RSVD3 [196] ; volatile Uint32 PCIVENDEVMIR ; volatile Uint32 PCICSRMIR ; volatile Uint32 PCICLREVMIR ; volatile Uint32 PCICLINEMIR ; volatile Uint32 PCIBAR0MSK ; volatile Uint32 PCIBAR1MSK ; volatile Uint32 PCIBAR2MSK ; volatile Uint32 PCIBAR3MSK ; volatile Uint32 PCIBAR4MSK ; volatile Uint32 PCIBAR5MSK ; volatile Uint8 RSVD4[4] ; volatile Uint32 PCISUBIDMIR ; volatile Uint8 RSVD5 [4] ; volatile Uint32 PCICPBPTRMIR ; volatile Uint8 RSVD6 [4] ; volatile Uint32 PCILGINTMIR ; volatile Uint8 RSVD7 [64] ; volatile Uint32 PCISLVCNTL ; volatile Uint8 RSVD8 [60] ; volatile Uint32 PCIBAR0TRL ; volatile Uint32 PCIBAR1TRL ; volatile Uint32 PCIBAR2TRL ; volatile Uint32 PCIBAR3TRL ; volatile Uint32 PCIBAR4TRL ; volatile Uint32 PCIBAR5TRL ; volatile Uint8 RSVD9 [8] ; volatile Uint32 PCIBARMIR [6] ; volatile Uint8 RSVD10 [264] ; volatile Uint32 PCIMCFGDAT ; volatile Uint32 PCIMCFGADR ; volatile Uint32 PCIMCFGCMD ; volatile Uint8 RSVD11 [4] ; volatile Uint32 PCIMSTCFG ; volatile Uint32 PCIADDSUB [32] ; volatile Uint32 PCIVENDEVPRG ; volatile Uint32 PCICMDSTATPRG ; volatile Uint32 PCICLREVPRG ; volatile Uint32 PCISUBIDPRG ; volatile Uint32 PCIMAXLGPRG ; volatile Uint32 PCILRSTREG ; volatile Uint32 PCICFGDONE ; volatile Uint32 PCIBAR0MPRG ; volatile Uint32 PCIBAR1MPRG ; volatile Uint32 PCIBAR2MPRG ; volatile Uint32 PCIBAR3MPRG ; volatile Uint32 PCIBAR4MPRG ; volatile Uint32 PCIBAR5MPRG ; volatile Uint32 PCIBAR0PRG ; volatile Uint32 PCIBAR1PRG ; volatile Uint32 PCIBAR2PRG ; volatile Uint32 PCIBAR3PRG ; volatile Uint32 PCIBAR4PRG ; volatile Uint32 PCIBAR5PRG ; volatile Uint32 PCIBAR0TRLPRG ; volatile Uint32 PCIBAR1TRLPRG ; volatile Uint32 PCIBAR2TRLPRG ; volatile Uint32 PCIBAR3TRLPRG ; volatile Uint32 PCIBAR4TRLPRG ; volatile Uint32 PCIBAR5TRLPRG ; volatile Uint32 PCIBASENPRG ; } DM64LCPCI_pciRegs ; struct pci_dev * GEM = NULL ; Uint32 regBase = 0 ; Uint32 memBase = 0 ; Uint32 ddrRegBase = 0 ; Uint32 * regVirt = NULL ; Uint32 * memVirt = NULL ; Uint32 * ddrRegVirt = NULL ; Uint32 memLen = 0 ; Uint32 regLen = 0 ; Uint32 ddrRegLen = 0 ; Int32 irqNo ; /* ============================================================================ * @func PCI_FindPciDevices * * @desc This function locates DM642 PCI cards on system. * * @modif None. * ============================================================================ */ Void PCI_FindPciDevices (Void) { struct pci_dev * dev = NULL ; while ((dev = pci_find_device (PCI_TI_VENDOR, PCI_TI_DEVICE, dev)) != NULL) { irqNo = dev->irq ; GEM = dev ; break ; } } /* ============================================================================ * @func PCI_readBAR * * @desc This function reads config. * * @modif None. * ============================================================================ */ Void PCI_readBAR (Void) { Uint32 barStart [3] ; Uint32 barLen [3] ; Uint32 barFlags [3] ; barStart [0] = pci_resource_start (GEM, 0); barLen [0] = pci_resource_len (GEM, 0); barFlags [0] = pci_resource_flags (GEM, 0); barStart [1] = pci_resource_start (GEM, 1); barLen [1] = pci_resource_len (GEM, 1); barFlags [1] = pci_resource_flags (GEM, 1); barStart [2] = pci_resource_start (GEM, 2); barLen [2] = pci_resource_len (GEM, 2); barFlags [2] = pci_resource_flags (GEM, 2); /* --------------------------------------------------------------------- * Map the L2RAM memory region * --------------------------------------------------------------------- */ if (barFlags [0] & IORESOURCE_MEM) { memBase = barStart [0] ; /* Map the memory region. */ request_mem_region (memBase, barLen [0], "DSPLINK"); } else { /* Map the memory region. */ request_region (memBase, barLen [0], "DSPLINK"); } if (memBase > 0) { memVirt = ioremap (barStart [0], barLen [0]) ; } /* --------------------------------------------------------------------- * Map the DDR REG memory region * --------------------------------------------------------------------- */ if (barFlags [1] & IORESOURCE_MEM) { ddrRegBase = barStart [1] ; /* Map the memory region. */ request_mem_region (ddrRegBase, barLen [1], "DSPLINK"); } else { /* Map the memory region. */ request_region (ddrRegBase, barLen [1], "DSPLINK"); } if (ddrRegBase > 0) { ddrRegVirt = ioremap (barStart [1], barLen [1]) ; } /* --------------------------------------------------------------------- * Map the REG memory region * --------------------------------------------------------------------- */ if (barFlags [2] & IORESOURCE_MEM) { regBase = barStart [2] ; /* Map the memory region. */ request_mem_region (regBase, barLen [2], "DSPLINK"); } else { /* Map the memory region. */ request_region (regBase, barLen [2], "DSPLINK"); } if (regBase > 0) { regVirt = ioremap (barStart [2], barLen [2]) ; } memLen = barLen [0] ; ddrRegLen = barLen [1] ; regLen = barLen [2] ; } /* ============================================================================= * @func PCI_setMaster * * @desc This function makes the given device to be master. * * @modif None. * ============================================================================ */ Void PCI_setMaster (void) { Int32 retVal ; Uint16 cmdVal ; struct pci_dev * dev ; dev = GEM ; /* set the DMA mask */ if (pci_set_dma_mask (dev, 0xfffffff0ULL)) { } /* * set the desired PCI dev to be master, this internally sets the latency * timer. */ pci_set_master (dev) ; pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80); /* Add support memory write invalidate */ retVal = pci_set_mwi (dev) ; pci_read_config_word (dev, PCI_COMMAND, (u16 *) &cmdVal) ; /* and set the master bit in command register. */ cmdVal |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR ; /* and clear the interrupt disable bit in command register. */ cmdVal &= ~PCI_COMMAND_INTX_DISABLE; pci_write_config_word (dev, PCI_COMMAND, cmdVal) ; } /* ============================================================================= * @func HAL_CheckPciInterrupt * * @desc This function check whether interrupt is generated by DM642 or not. * * @modif None. * ============================================================================ */ Bool HAL_CheckPciInterrupt (void) { volatile DM64LCPCI_pciRegs * pciRegs = (DM64LCPCI_pciRegs *) ((Uint32) regVirt + (DM64LCPCI_PCIREG_BASE - 0x01C00000)) ; Bool status = 0 ; if ( (pciRegs->PCICSRMIR & DM64LCPCI_INTSTATUS_MASK) == (DM64LCPCI_INTSTATUS_MASK)) { status = 1 ; } return status ; } /** ============================================================================ * @func HAL_PciClearDspInterrupt * * @desc Clear pending interrupt from DSP to Host. * * @modif None. * ============================================================================ */ Void HAL_PciClearDspInterrupt (Void) { volatile DM64LCPCI_pciRegs * pciRegs = (DM64LCPCI_pciRegs *) ((Uint32) regVirt + (DM64LCPCI_PCIREG_BASE - 0x01C00000)) ; pciRegs->PCISTATCLR |= DM64LCPCI_SOFTINT0_MASK ; } /** ============================================================================ * @func HAL_PciEnableDspInterrupt * * @desc Allow the DSP to generate interrupts to the Host. * * @modif None. * ============================================================================ */ Void HAL_PciEnableDspInterrupt (Void) { volatile DM64LCPCI_pciRegs * pciRegs = (DM64LCPCI_pciRegs *) ((Uint32) regVirt + (DM64LCPCI_PCIREG_BASE - 0x01C00000)) ; pciRegs->PCIHINTSET |= DM64LCPCI_SOFTINT0_MASK ; } /** ============================================================================ * @func HAL_PciDisableDspInterrupt * * @desc Disallow the DSP to generate interrupts to the Host. * * @modif None. * ============================================================================ */ Void HAL_PciDisableDspInterrupt (Void) { volatile DM64LCPCI_pciRegs * pciRegs = (DM64LCPCI_pciRegs *) ((Uint32) regVirt + (DM64LCPCI_PCIREG_BASE - 0x01C00000)) ; pciRegs->PCIHINTCLR |= DM64LCPCI_SOFTINT0_MASK ; } /* ---------------------------------------------------------------------------- * @func HAL_changeState * * @desc Change power module state to ( ENABLE, DISABLE, SYNCRESET, RESET ). * * @modif None * ---------------------------------------------------------------------------- */ Void HAL_changeState (Uint32 lpscNum, Uint16 state) { volatile DM64LCPCI_pscRegs * pscRegs = (DM64LCPCI_pscRegs *) ((Uint32) regVirt + (DM64LCPCI_PSCREG_BASE - 0x01C00000)) ; if ((pscRegs->MDSTAT [lpscNum] & 0x001F) == state) { return ; } /* ------------------------------------------------------------------------ * Step 1 - Wait for PTSTAT.GOSTAT to clear * ------------------------------------------------------------------------ */ while (pscRegs->PTSTAT & 0x1) ; /* ------------------------------------------------------------------------ * Step 2 - Set MDCTLx.NEXT to new state * ------------------------------------------------------------------------ */ pscRegs->MDCTL [lpscNum] &= 0xFFE0 ; pscRegs->MDCTL [lpscNum] |= state ; /* ------------------------------------------------------------------------ * Step 3 - Start power transition ( set PTCMD.GO to 1 ) * ------------------------------------------------------------------------ */ pscRegs->PTCMD = 0x0001 ; /* ------------------------------------------------------------------------ * Step 4 - Wait for PTSTAT.GOSTAT to clear * ------------------------------------------------------------------------ */ while (pscRegs->PTSTAT & 0x1) ; /* ------------------------------------------------------------------------ * Step 5 - Verify state changed * ------------------------------------------------------------------------ */ while ((pscRegs->MDSTAT [lpscNum] & 0x001F) != state) ; } /* ---------------------------------------------------------------------------- * @func HAL_cfgPLL1 * * @desc Configures the PLL1. * * @modif None * ---------------------------------------------------------------------------- */ Void HAL_cfgPLL1 (Uint32 pllm, Uint32 div1, Uint32 div2) { volatile DM64LCPCI_pllRegs * pllRegs = (DM64LCPCI_pllRegs *) ((Uint32) regVirt + (DM64LCPCI_PLL1REG_BASE - 0x01C00000)) ; /* ------------------------------------------------------------------------ * Step 1 - Set PLL to BYPASS mode and select clock source. * ------------------------------------------------------------------------ */ pllRegs->PLLCTL &= 0xFFFFFEFF ; pllRegs->PLLCTL |= 0x0 ; pllRegs->PLLCTL &= 0xFFFFFFDF ; pllRegs->PLLCTL &= 0xFFFFFFFE ; udelay (10000) ; pllRegs->PLLCTL &= 0xFFFFFFF7 ; pllRegs->PLLCTL |= 0x00000010 ; pllRegs->PLLCTL &= 0xFFFFFFFD ; pllRegs->PLLCTL &= 0xFFFFFFEF ; pllRegs->PLLCTL &= 0xFFFFFEFF ; pllRegs->PLLCTL |= 0x0 ; /* ------------------------------------------------------------------------ * Step 2 - Load PLL multiplier. * ------------------------------------------------------------------------ */ pllRegs->PLLM = pllm ; /* ------------------------------------------------------------------------ * Step 3 - Load PLL2 divider - DDR2 and VPBE are programmable. * ------------------------------------------------------------------------ */ pllRegs->PLLDIV1 = div2 ; pllRegs->PLLDIV2 = div1 ; pllRegs->PLLDIV1 &= 0xFFFF7FFF ; pllRegs->PLLDIV2 &= 0xFFFF7FFF ; pllRegs->PLLDIV1 |= 0x00008000 ; pllRegs->PLLDIV2 |= 0x00008000 ; /* ------------------------------------------------------------------------ * Step 4 - Set phase alignment and Wait for operation to finish. * ------------------------------------------------------------------------ */ pllRegs->PLLCMD |= 0x00000001 ; while ((pllRegs->PLLSTAT & 0x1) == 0x1) ; /* ------------------------------------------------------------------------ * Step 5 - Wait for PLL to re-lock ( 2000 cycles ). * ------------------------------------------------------------------------ */ udelay (10000) ; pllRegs->PLLCTL |= 0x00000008 ; /* ------------------------------------------------------------------------ * Step 6 - Switch out of BYPASS mode. * ------------------------------------------------------------------------ */ udelay (10000) ; pllRegs->PLLCTL |= 0x00000001 ; } /* ---------------------------------------------------------------------------- * @func HAL_cfgDDR2 * * @desc Configures the DDR2 module. * * @modif None * ---------------------------------------------------------------------------- */ Void HAL_cfgDDR2 (Uint32 freq) { volatile DM64LCPCI_ddrRegs * ddrRegs = (DM64LCPCI_ddrRegs *) ((Uint32) ddrRegVirt) ; Uint32 * vtpiocr = NULL ; Uint32 * vtpr = NULL ; Uint32 * dftEnb = NULL ; vtpiocr = (Uint32 *) ((Uint32) ddrRegVirt + 0xF0) ; vtpr = (Uint32 *) ((Uint32) regVirt + 0x42038) ; dftEnb = (Uint32 *) ((Uint32) regVirt + 0x4004C) ; /* Enable the DDR2 PSC Module */ HAL_changeState (13, 0x3) ; /* ------------------------------------------------------------------------ * Step 1. Enable DDR2 PHY. * ------------------------------------------------------------------------ */ ddrRegs->DDRPHYCR = 0x50006405 ; ddrRegs->SDBCR = 0x00138822 ; ddrRegs->SDTIMR = 0x16492148 ; ddrRegs->SDTIMR2 = 0x000CC702 ; ddrRegs->SDBCR = 0x00130822 ; /* ------------------------------------------------------------------------ * Step 3. Refresh Control [ 7.8 usec * freq in MHz ]. * ------------------------------------------------------------------------ */ ddrRegs->SDRCR = 0x4EF ; /* Reset the DDR2 PSC Module */ HAL_changeState (13, 0x1) ; HAL_changeState (13, 0x3) ; /* ------------------------------------------------------------------------ * Step 4. Enable VTP calibration * ------------------------------------------------------------------------ */ *vtpiocr = 0x201F ; *vtpiocr = 0xA01F ; /* wait for 33 VTP clock cycles */ udelay (10000); *dftEnb = 1 ; *vtpiocr = 0xA000 | (*vtpr | 0x3FF) ; /* Wait for few more clock cycles */ udelay (10000); *vtpiocr &= 0xFFFFDFFF ; *dftEnb = 0 ; } /* ============================================================================ * @func HAL_readDMA * * @desc DMAs contents from DSP memory to GPP Memory. Here read means DSP * write. * * @modif None. * ============================================================================ */ Void HAL_readDMA (Uint32 srcAddr, Uint32 dstAddr, Uint32 size) { volatile DM64LCPCI_edmaRegs * edmaRegs = (DM64LCPCI_edmaRegs *) ((Uint32) regVirt + (DM64LCPCI_EDMAREG_BASE - 0x01C00000)) ; volatile DM64LCPCI_pciRegs * pciRegs = (DM64LCPCI_pciRegs *) ((Uint32) regVirt + (DM64LCPCI_PCIREG_BASE - 0x01C00000)) ; Uint32 i = 0 ; Uint32 pageBase ; Uint32 numUSec ; Uint32 tSize ; Uint32 tmp ; if (size <= DM64LCPCI_PCIADLEN) { pageBase = dstAddr & DM64LCPCI_PCIADWRBITMASK ; pciRegs->PCIADDSUB [0] = pageBase ; } else { for (tmp = size, i = 0 ; tmp > 0 ; tmp -= DM64LCPCI_PCIADLEN, i++) { pageBase = (dstAddr + (DM64LCPCI_PCIADLEN * i)) & DM64LCPCI_PCIADWRBITMASK ; pciRegs->PCIADDSUB [i] = pageBase ; } } do { /* Set the interrupt enable for 1st Channel. */ edmaRegs->IESR |= 0x1 ; /* Clear any pending interrupt. */ edmaRegs->ICR |= 0x1 ; /* Populate the Param entry. */ edmaRegs->PARAMENTRY [0].OPTION = 0x00100004 ; edmaRegs->PARAMENTRY [0].SRC = srcAddr ; /* Calculate the DSP PCI address for the PC address */ tmp = 0x30000000 + (dstAddr & ~DM64LCPCI_PCIADWRBITMASK) ; edmaRegs->PARAMENTRY [0].DST = tmp ; /* Calculate the A & B count */ if (size > 0x7000) { tmp = size / 0x7000 ; tSize = tmp * 0x7000 ; size -= (tmp * 0x7000) ; tmp <<= 16 ; tmp |= 0x7000 ; } else { tmp = 0x10000 | size ; tSize = size ; size = 0 ; } edmaRegs->PARAMENTRY [0].A_B_CNT = tmp ; edmaRegs->PARAMENTRY [0].LINK_BCNTRLD = 0xFFFF ; edmaRegs->PARAMENTRY [0].SRC_DST_CIDX = 0 ; /* C Count is set to 1 since mostly size will not be more than 1GB */ edmaRegs->PARAMENTRY [0].CCNT = 0x1 ; /* no offset difference required */ edmaRegs->PARAMENTRY [0].SRC_DST_BIDX = 0x70007000 ; /* Set the interrupt enable for 1st Channel. */ edmaRegs->EESR |= 0x1 ; /* Clear any pending interrupt. */ edmaRegs->ESR |= 0x1 ; /* wait for current DMA to finish. */ numUSec = tSize / 132 ; do { udelay (numUSec) ; /* now check in steps of 10 usec. */ numUSec = 10 ; } while ((edmaRegs->IPR & 0x1) == 0) ; if (size != 0) { srcAddr += tSize ; dstAddr += tSize ; } } while (size != 0) ; /* Clear any pending interrupt. */ edmaRegs->ICR |= 0x1 ; } /* ============================================================================ * @func HAL_writeDMA * * @desc DMAs contents from GPP memory to DSP Memory. Here write means DSP * read. * * @modif None. * ============================================================================ */ Void HAL_writeDMA (Uint32 srcAddr, Uint32 dstAddr, Uint32 size) { volatile DM64LCPCI_edmaRegs * edmaRegs = (DM64LCPCI_edmaRegs *) ((Uint32) regVirt + (DM64LCPCI_EDMAREG_BASE - 0x01C00000)) ; volatile DM64LCPCI_pciRegs * pciRegs = (DM64LCPCI_pciRegs *) ((Uint32) regVirt + (DM64LCPCI_PCIREG_BASE - 0x01C00000)) ; Uint32 i = 0 ; Uint32 pageBase ; Uint32 numUSec ; Uint32 tmp ; Uint32 tSize ; if (size <= DM64LCPCI_PCIADLEN) { pageBase = srcAddr & DM64LCPCI_PCIADWRBITMASK ; pciRegs->PCIADDSUB [0] = pageBase ; } else { for (tmp = size, i = 0 ; tmp > 0 ; tmp -= DM64LCPCI_PCIADLEN, i++) { pageBase = (srcAddr + (DM64LCPCI_PCIADLEN * i)) & DM64LCPCI_PCIADWRBITMASK ; pciRegs->PCIADDSUB [i] = pageBase ; } } do { /* Set the interrupt enable for 1st Channel. */ edmaRegs->IESR |= 0x1 ; /* Clear any pending interrupt. */ edmaRegs->ICR |= 0x1 ; /* Populate the Param entry. */ edmaRegs->PARAMENTRY [0].OPTION = 0x00100004 ; /* Calculate the DSP PCI address for the PC address */ tmp = 0x30000000 + (srcAddr & ~DM64LCPCI_PCIADWRBITMASK) ; edmaRegs->PARAMENTRY [0].SRC = tmp ; edmaRegs->PARAMENTRY [0].DST = dstAddr ; /* Calculate the A & B count */ if (size > 0x7000) { tmp = size / 0x7000 ; tSize = tmp * 0x7000 ; size -= (tmp * 0x7000) ; tmp <<= 16 ; tmp |= 0x7000 ; } else { tmp = 0x10000 | size ; tSize = size ; size = 0 ; } edmaRegs->PARAMENTRY [0].A_B_CNT = tmp ; edmaRegs->PARAMENTRY [0].LINK_BCNTRLD = 0xFFFF ; edmaRegs->PARAMENTRY [0].SRC_DST_CIDX = 0 ; /* no offset difference required */ edmaRegs->PARAMENTRY [0].SRC_DST_BIDX = 0x70007000 ; /* C Count is set to 1 since mostly size will not be more than 1GB */ edmaRegs->PARAMENTRY [0].CCNT = 0x1 ; /* Set the interrupt enable for 1st Channel. */ edmaRegs->EESR |= 0x1 ; /* Clear any pending interrupt. */ edmaRegs->ESR |= 0x1 ; /* wait for current DMA to finish. */ numUSec = tSize / 132 ; do { udelay (numUSec) ; /* now check in steps of 10 usec. */ numUSec = 10 ; } while ((edmaRegs->IPR & 0x1) == 0) ; if (size != 0) { srcAddr += tSize ; dstAddr += tSize ; } } while (size != 0) ; /* Clear any pending interrupt. */ edmaRegs->ICR |= 0x1 ; } #define ADDR32(x) *((Uint32 *) ((Uint32)memVirt + x)) /** ============================================================================ * @const LPSC_EDMA_TPCC * * @desc Module number for EDMA TPCC. * ============================================================================ */ #define LPSC_EDMA_TPCC 2 /** ============================================================================ * @const LPSC_EDMA_TPTC0 * * @desc Module number for EDMA TPTC0. * ============================================================================ */ #define LPSC_EDMA_TPTC0 3 /** ============================================================================ * @const LPSC_EDMA_TPTC1 * * @desc Module number for EDMA TPTC1. * ============================================================================ */ #define LPSC_EDMA_TPTC1 4 static irqreturn_t ISR_handler (int irq, void * arg, struct pt_regs * flags) { Uint32 status = HAL_CheckPciInterrupt () ; if (status == 1) { HAL_PciClearDspInterrupt () ; printk ("Interrupt %d received from DSP\n", irq) ; return IRQ_HANDLED; } return IRQ_NONE; } Uint32 dummy ; int init_module(void) { Uint32 i; Uint32 j; Uint8 * wData ; Uint8 * rData ; wData = (Uint8 *) kmalloc (0x8000, GFP_DMA) ; rData = (Uint8 *) kmalloc (0x8000, GFP_DMA) ; printk ("<1>Finding the device....\n") ; PCI_FindPciDevices () ; if (GEM != NULL) { printk ("<1>Reading the BAR areas....\n") ; PCI_readBAR () ; printk ("<1>Enabling the device....\n") ; pci_enable_device (GEM) ; pci_set_drvdata (GEM, memVirt) ; PCI_setMaster () ; printk ("<1>Registering the irq\n") ; request_irq (irqNo, ISR_handler, SA_SHIRQ, "PCIDRV", &dummy) ; HAL_PciEnableDspInterrupt () ; printk ("<1>Powering EDMA engine....\n") ; HAL_changeState (LPSC_EDMA_TPCC, 0x3) ; HAL_changeState (LPSC_EDMA_TPTC0, 0x3) ; HAL_changeState (LPSC_EDMA_TPTC1, 0x3) ; printk ("<1>PConfiguring the PLL1....\n") ; HAL_cfgPLL1 (23, 11, 1) ; printk ("<1>Configuring the DDR2....\n") ; HAL_cfgDDR2 (162) ; printk ("<1>Running memory test....\n") ; { volatile Uint32 * ptr = (Uint32 *) memVirt ; int i ; for (j = 0 ; j < 1000 ; j++) { printk ("<1>Initializing memory....%d\n", j) ; /* Initialize the buffer */ for (i = 0 ; i < 0x8000; i++) { ptr [i] = i ; } printk ("<1>Reading back memory....%d\n", j) ; /* read the buffer back */ for (i = 0 ; i < 0x8000; i++) { if (ptr [i] != i) { printk ("<1> Memory test failed at 0x%08x\n", 0x10800000+(i*4)) ; } } } } /* If you see failure prints before this, means test failed */ printk ("<1>Memory test passed....\n") ; printk ("<1>Running DMA test....\n") ; if (wData && rData) { printk ("<1>Initializing memory....\n") ; for (i = 0 ; i < 0x8000; i++) { wData [i] = 0xAB ; rData [i] = 0x00 ; } printk ("<1>Write DMA to DSP....\n") ; HAL_writeDMA ((Uint32) virt_to_bus (wData), 0x80100000, 0x8000) ; printk ("<1>Read DMA to DSP....\n") ; HAL_readDMA (0x80100000, (Uint32) virt_to_bus (rData), 0x8000) ; if ((rData [0] == wData [0]) && (wData [0x4000] == rData [0x4000])) { printk ("API DMA passed\n") ; } else { printk ("API DMA failed %x\n", rData [0]) ; } } printk ("<1>Generating the irq\n") ; { volatile DM64LCPCI_pciRegs * pciRegs = (DM64LCPCI_pciRegs *) ( (Uint32) regVirt + (DM64LCPCI_PCIREG_BASE - 0x01C00000)) ; pciRegs->PCISTATSET |= DM64LCPCI_SOFTINT0_MASK ; } } else { printk ("<1>No PCI device found!!!\n") ; } kfree (rData) ; kfree (wData) ; return 0 ; } void cleanup_module(void) { if (GEM != NULL) { HAL_PciDisableDspInterrupt () ; iounmap(memVirt) ; if (pci_resource_flags (GEM, 0) & IORESOURCE_MEM) { /* Map the memory region. */ release_mem_region (memBase, memLen); } else { /* Map the memory region. */ release_region (memBase, memLen); } /* --------------------------------------------------------------------- * Unmap baseRegs region & release the reg region. * --------------------------------------------------------------------- */ iounmap(ddrRegVirt) ; if (pci_resource_flags (GEM, 1) & IORESOURCE_MEM) { /* Map the memory region. */ release_mem_region (ddrRegBase, ddrRegLen); } else { /* Map the memory region. */ release_region (ddrRegBase, ddrRegLen); } /* --------------------------------------------------------------------- * Unmap baseRegs region & release the reg region. * --------------------------------------------------------------------- */ iounmap(regVirt) ; if (pci_resource_flags (GEM, 2) & IORESOURCE_MEM) { /* Map the memory region. */ release_mem_region (regBase, regLen); } else { /* Map the memory region. */ release_region (regBase, regLen); } free_irq (irqNo, &dummy) ; } }
KDIR=/usr/src/kernels/linux-2.6.21.7 PWD=$(shell pwd) obj-m = pcidrv.o all: $(MAKE) -C $(KDIR) M=$(PWD) clean: rm -fr *.o *.mod.c *.ko
Usage[edit]
- Copy the c code into a file called pcidrv.c
- Copy it to the Linux workstation
- Copy the gmake syntax to a file called Makefile
- Copy it also to the same directory where c code was copied.
- Then issue the following command.
- $make
- Output of this command is pcidrv.ko file
- Run it as follows: $insmod pcidrv.ko
- Type the following command to see the output: $dmesg