]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/mcsdk-tools.git/blob - boot_loader/examples/pcie/linux_host_loader/pciedemo.c
2360d14199bb410b767130b660ec989b06e487c6
[keystone-rtos/mcsdk-tools.git] / boot_loader / examples / pcie / linux_host_loader / pciedemo.c
1 /******************************************************************************
2  * Copyright (c) 2011 Texas Instruments Incorporated - http://www.ti.com
3  * 
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as 
6  * published by the Free Software Foundation version 2.
7  *
8  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9  * kind, whether express or implied; without even the implied warranty
10  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *****************************************************************************/
14 /**************************************************************************************
15  * FILE NAME: pciedemo.c
16  *
17  * DESCRIPTION: A sample code to load DSP boot image from a Linux machine into DSP.
18  *
19  * Revision History:
20  *    - 1.0:  Initial version (6678 little endian PCIE boot POST demo)
21  *    - 1.1:  Add a new PCIE boot demo for HelloWorld
22  *    - 1.2:  support 6670 boot
23  *    - 1.3:  support big endian boot for 6670/6678; support 32-bit/64-bit Linux;         
24  *            support EDMA; support interrupt between host and DSP; 
25  *            added PCIE over EDMA throughput measurement  
26  ***************************************************************************************/
28 #include <linux/module.h>
29 #include <linux/types.h>
30 #include <linux/kernel.h>
31 #include <linux/pci.h>
32 #include <linux/delay.h>
33 #include <linux/fs.h>
34 #include <linux/init.h>
35 #include <linux/ioport.h>
36 #include <linux/interrupt.h>
37 #include <asm/uaccess.h>
38 #include <asm/dma-mapping.h>
39 #include <linux/time.h>
41 MODULE_LICENSE("GPL v2");
43 /* Must select the endianess */
44 #define BIG_ENDIAN          0
46 /* Must select which demo to run */ 
47 #define HELLO_WORLD_DEMO    1
48 #define POST_DEMO           0 
49 #define EDMA_INTC_DEMO      0 
51 /* Must select a platform */
52 #define EVMC6678L           1
53 #define EVMC6670L           0
55 #if BIG_ENDIAN
56 #define myIoread32  ioread32be
57 #define myIowrite32 iowrite32be
58 #else
59 #define myIoread32  ioread32 
60 #define myIowrite32 iowrite32
61 #endif
63 #if EVMC6678L
64 #define MAGIC_ADDR          0x0087FFFC
65 #endif
67 #if EVMC6670L
68 #define MAGIC_ADDR          0x008FFFFC
69 #endif
71 /* Include header array */
72 #if HELLO_WORLD_DEMO
74 #if EVMC6678L
75 #include "pcieDdrInit_6678.h"     /* DDR init */
76 #include "pcieBootCode_6678.h"    /* "Hello world" boot example */  
77 #endif
79 #if EVMC6670L
80 #include "pcieDdrInit_6670.h"     /* DDR init */
81 #include "pcieBootCode_6670.h"    /* "Hello world" boot example */
82 #endif
84 #endif
86 #if POST_DEMO
88 #if EVMC6678L
89 #include "post_6678.h"            /* POST boot example */
90 #endif
92 #if EVMC6670L
93 #include "post_6670.h"            /* POST boot example */
94 #endif
96 #endif
98 #if EDMA_INTC_DEMO
100 #if EVMC6678L
101 #include "pcieInterrupt_6678.h"   /* EDMA-Interrupt boot example */
102 #endif
104 #if EVMC6670L
105 #include "pcieInterrupt_6670.h"   /* EDMA-Interrupt boot example */
106 #endif
108 #endif
110 /* PCIE registers */
111 #define PCIE_BASE_ADDRESS            0x21800000
112 #define OB_SIZE                      0x30
113 #define EP_IRQ_CLR                   0x68
114 #define EP_IRQ_STATUS                0x6C
115 #define LEGACY_A_IRQ_STATUS_RAW      0x180
116 #define LEGACY_A_IRQ_ENABLE_SET      0x188
117 #define LEGACY_A_IRQ_ENABLE_CLR      0x18C
118 #define OB_OFFSET_INDEX(n)           (0x200 + (8 * n))
119 #define OB_OFFSET_HI(n)              (0x204 + (8 * n))
120 #define IB_BAR(n)                    (0x300 + (0x10 * n))
121 #define IB_START_LO(n)               (0x304 + (0x10 * n))
122 #define IB_START_HI(n)               (0x308 + (0x10 * n))
123 #define IB_OFFSET(n)                 (0x30C + (0x10 * n))
125 #define PCIE_TI_VENDOR               0x104C
126 #define PCIE_TI_DEVICE               0xB005
128 /* EDMA registers */
129 #define EDMA_TPCC0_BASE_ADDRESS      0x02700000
130 #define DMAQNUM0                     0x0240  
131 #define ESR                          0x1010 
132 #define EESR                         0x1030                 
133 #define IESR                         0x1060
134 #define IPR                          0x1068 
135 #define ICR                          0x1070 
136 #define PARAM_0_OPT                  0x4000
137 #define PARAM_0_SRC                  0x4004
138 #define PARAM_0_A_B_CNT              0x4008
139 #define PARAM_0_DST                  0x400C
140 #define PARAM_0_SRC_DST_BIDX         0x4010
141 #define PARAM_0_LINK_BCNTRLD         0x4014
142 #define PARAM_0_SRC_DST_CIDX         0x4018
143 #define PARAM_0_CCNT                 0x401C
145 #define LL2_START                    0x00800000
146 #define MSMC_START                   0x0C000000  /* Shared L2 */
147 #define DDR_START                    0x80000000
148 #define PCIE_DATA                    0x60000000  
150 /* Block size in bytes when r/w data between GPP and DSP via DSP CPU */
151 #define BLOCK_TRANSFER_SIZE          0x100      
153 /* Data size in bytes when r/w data bewteen GPP and DSP via EDMA:
154    GPP----PCIE link----PCIE data space----EDMA----DSP device memory (L2, DDR, ...) */
155 #define DMA_TRANSFER_SIZE            0x400000   /* 4MB */
157 /* Payload size in bytes over PCIE link. PCIe module supports 
158    outbound payload size of 128 bytes and inbound payload size of 256 bytes */
159 #define PCIE_TRANSFER_SIZE           0x80               
161 /* For 1MB outbound translation window size */
162 #define PCIE_ADLEN_1MB               0x00100000
163 #define PCIE_1MB_BITMASK             0xFFF00000
165 /* 
166 reg:  PCIE application registers
167 mem:  Local L2
168 msmc: Shared L2 memory
169 ddr:  DDR3   
170  */
172 uint8_t *wDataVirt, *rDataVirt;          /* Virtue address for CPU */
173 dma_addr_t wData, rData;                 /* Physical PCIE bus address */
176 /***********************************************
177  * uncomment following line on very old kernels:
178  * typedef unsigned long resource_size_t;
179  **********************************************/
180 resource_size_t regBase = 0;
181 resource_size_t memBase = 0;
182 resource_size_t msmcBase = 0;
183 resource_size_t ddrBase = 0;
185 uint32_t *regVirt = NULL;
186 uint32_t *memVirt = NULL;
187 uint32_t *msmcVirt = NULL;
188 uint32_t *ddrVirt = NULL;
190 resource_size_t memLen = 0;
191 resource_size_t regLen = 0;
192 resource_size_t msmcLen = 0;
193 resource_size_t ddrLen = 0;
195 uint32_t *ptrReg = 0; 
196 int32_t  irqNo;
197 uint32_t dummy;
198 struct pci_dev *PCIE_DEV = NULL;
200 struct timeval test_time1;
201 struct timeval test_time2;
202 struct timeval test_time3;
203 struct timeval test_time4;
205 /* ============================================================================
206  *  @func   PCI_FindPciDevices
207  *
208  *  @desc   This function locates 6670/6678 PCIE cards on system.
209  *
210  *  @modif  None.
211  *  ============================================================================
212  */
213 void PCI_FindPciDevices(void)
215         struct pci_dev *dev = NULL;
217         while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
218         {
219                 if ((dev->vendor == PCIE_TI_VENDOR) && (dev->device == PCIE_TI_DEVICE)) {
220                         printk("Found TI device\n");
221                         irqNo = dev->irq;
222                         PCIE_DEV = dev;
223                         printk("TI device: vendor=0x%04x, dev=0x%04x, irq=0x%08x\n", dev->vendor, dev->device, dev->irq);
224                         break;
225                 }
226         }
229 /* ============================================================================
230  *  @func   PCI_readBAR
231  *
232  *  @desc   This function reads config.
233  *
234  *  @modif  None.
235  *  ============================================================================
236  */
237 void PCI_readBAR(void)
239         resource_size_t  barStart[4];
240         resource_size_t  barLen[4];
241         resource_size_t  barFlags[4];
243         barStart [0] = pci_resource_start (PCIE_DEV, 0);   /* BAR0 4K for PCIE application registers */
244         barLen   [0] = pci_resource_len   (PCIE_DEV, 0);
245         barFlags [0] = pci_resource_flags (PCIE_DEV, 0);
246         barStart [1] = pci_resource_start (PCIE_DEV, 1);   /* BAR1 512K/1024K for 6678/6670 Local L2 */
247         barLen   [1] = pci_resource_len   (PCIE_DEV, 1);
248         barFlags [1] = pci_resource_flags (PCIE_DEV, 1);
249         barStart [2] = pci_resource_start (PCIE_DEV, 2);   /* BAR2 4M/2M for 6678/6670 Shared L2 */
250         barLen   [2] = pci_resource_len   (PCIE_DEV, 2);
251         barFlags [2] = pci_resource_flags (PCIE_DEV, 2);
252         barStart [3] = pci_resource_start (PCIE_DEV, 3);   /* BAR3 16M for DDR3 */
253         barLen   [3] = pci_resource_len   (PCIE_DEV, 3);
254         barFlags [3] = pci_resource_flags (PCIE_DEV, 3);
256         /* ---------------------------------------------------------------------
257          * Map the REG memory region
258          * ---------------------------------------------------------------------
259          */
260         if (barFlags[0] & IORESOURCE_MEM) {
261                 regBase = barStart[0];
262                 /* Map the memory region. */
263                 request_mem_region(regBase, barLen[0], "DSPLINK");
264         }
265         else {
266                 /* Map the memory region. */
267                 request_region(regBase, barLen[0], "DSPLINK");
268         }
270         if (regBase > 0) {
271                 regVirt = ioremap(barStart[0], barLen[0]);
272         }
274         /* ---------------------------------------------------------------------
275          * Map the LL2RAM memory region
276          * ---------------------------------------------------------------------
277          */
278         if (barFlags[1] & IORESOURCE_MEM) {
279                 memBase = barStart[1];
280                 /* Map the memory region. */
281                 request_mem_region(memBase, barLen[1], "DSPLINK");
282         }
283         else {
284                 /* Map the memory region. */
285                 request_region(memBase, barLen[1], "DSPLINK");
286         }
288         if (memBase > 0) {
289                 memVirt = ioremap(barStart[1], barLen[1]);
290         }
292         /* ---------------------------------------------------------------------
293          * Map the MSMC memory region
294          * ---------------------------------------------------------------------
295          */
296         if (barFlags[2] & IORESOURCE_MEM) {
297                 msmcBase = barStart[2];
298                 /* Map the memory region. */
299                 request_mem_region(msmcBase, barLen[2], "DSPLINK");
300         }
301         else {
302                 /* Map the memory region. */
303                 request_region(msmcBase, barLen[2], "DSPLINK");
304         }
306         if (msmcBase > 0) {
307                 msmcVirt = ioremap(barStart[2], barLen[2]);
308         }
310         /* ---------------------------------------------------------------------
311          * Map the DDR memory region
312          * ---------------------------------------------------------------------
313          */
314         if (barFlags[3] & IORESOURCE_MEM) {
315                 ddrBase = barStart[3];
316                 /* Map the memory region. */
317                 request_mem_region(ddrBase, barLen[3], "DSPLINK");
318         }
319         else {
320                 /* Map the memory region. */
321                 request_region(ddrBase, barLen[3], "DSPLINK");
322         }
324         if (ddrBase > 0) {
325                 ddrVirt = ioremap(barStart[3], barLen[3]);
326         }
328         regLen  = barLen[0];
329         memLen  = barLen[1];
330         msmcLen = barLen[2];
331         ddrLen  = barLen[3];
335 /* =============================================================================
336  *  @func   PCI_setMaster
337  *
338  *  @desc   This function makes the given device to be master.
339  *
340  *  @modif  None.
341  *  ============================================================================
342  */
343 void PCI_setMaster(void)
345         int32_t  retVal;
346         uint16_t cmdVal;
347         struct pci_dev *dev;
349         dev = PCIE_DEV;
351         /* set the DMA mask */
352         if (pci_set_dma_mask(dev, 0xfffffff0ULL)) {
353         }
355         /* set the desired PCI dev to be master, this internally sets the latency timer */
356         pci_set_master(dev);
357         pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
359         /* Add support memory write invalidate */
360         retVal = pci_set_mwi(dev);
362         pci_read_config_word(dev, PCI_COMMAND, (u16 *)&cmdVal);
363         /* and set the master bit in command register. */
364         cmdVal |= PCI_COMMAND_MEMORY
365                 | PCI_COMMAND_MASTER
366                 | PCI_COMMAND_SERR;
367         /* and clear the interrupt disable bit in command register. */
368         cmdVal &= ~PCI_COMMAND_INTX_DISABLE;
369         pci_write_config_word(dev, PCI_COMMAND, cmdVal);
372 /* =============================================================================
373  *  @func   HAL_CheckPciInterrupt
374  *
375  *  @desc   This function check whether interrupt is generated by C667x or not.
376  *
377  *  @modif  None.
378  *  ============================================================================
379  */
380 bool HAL_CheckPciInterrupt(void)
382         uint32_t *pReg = (uint32_t *)regVirt;
383         return ioread32(pReg + EP_IRQ_STATUS/4);
386 /** ============================================================================
387  *  @func   HAL_PciClearDspInterrupt
388  *
389  *  @desc   Clear pending interrupt from DSP to Host.
390  *
391  *  @modif  None.
392  *  ============================================================================
393  */
394 void HAL_PciClearDspInterrupt(void)
396         uint32_t *pReg = (uint32_t *)regVirt;
397         iowrite32(1, pReg+EP_IRQ_CLR/4);
400 /** ============================================================================
401  *  @func   HAL_PciEnableDspInterrupt
402  *
403  *  @desc   Allow the DSP to generate interrupts to the Host.
404  *
405  *  @modif  None.
406  *  ============================================================================
407  */
408 void HAL_PciEnableDspInterrupt(void)
410         uint32_t *pReg = (uint32_t *)regVirt;
411         iowrite32(1, pReg+LEGACY_A_IRQ_ENABLE_SET/4);
414 /** ============================================================================
415  *  @func   HAL_PciDisableDspInterrupt
416  *
417  *  @desc   Disable the DSP to generate interrupts to the Host.
418  *
419  *  @modif  None.
420  *  ============================================================================
421  */
422 void HAL_PciDisableDspInterrupt(void)
424         uint32_t *pReg = (uint32_t *)regVirt;
425         iowrite32(1, pReg+LEGACY_A_IRQ_ENABLE_CLR/4);
429 /* ============================================================================
430  *  @func   HAL_readDMA
431  *
432  *  @desc   Move DMAs contents from DSP memory to GPP Memory. For DSP this is
433  *          outbound write. 
434  *  flag:   0: Move data inside DSP; 1: Move data between GPP and DSP
435  *  
436  *  @modif  None.
437  *  ============================================================================
438  */
439 void HAL_readDMA(uint32_t srcAddr, uint32_t dstAddr, uint32_t size, uint32_t flag)
441         uint32_t *pReg, tmp, pageBase, i, tSize;
443         pReg = (uint32_t *)regVirt;     /* Point to PCIE application registers */
445         /* Move data between GPP and DSP, need to program PCIE OB registers */
446         if (flag) { 
447                 iowrite32(0x0, pReg + OB_SIZE/4); /* 1MB outbound translation size */
449                 if (size <= PCIE_ADLEN_1MB) {
450                         pageBase = dstAddr & PCIE_1MB_BITMASK;
451                         iowrite32(pageBase|0x1, pReg + OB_OFFSET_INDEX(0)/4);
452                         iowrite32(0x0, pReg + OB_OFFSET_HI(0)/4);  
453                 }
454                 else {
455                         for (tmp = size, i = 0; tmp > 0; tmp -= PCIE_ADLEN_1MB, i++) {
456                                 pageBase = (dstAddr + (PCIE_ADLEN_1MB * i)) & PCIE_1MB_BITMASK;
457                                 iowrite32(pageBase|0x1, pReg + OB_OFFSET_INDEX(i)/4);
458                                 iowrite32(0x0, pReg + OB_OFFSET_HI(i)/4);
459                         }
460                 }
461         }
463         /* Temporarily re-map IB region 3 from DDR memory to EDMA registers */
464         iowrite32(EDMA_TPCC0_BASE_ADDRESS, pReg + IB_OFFSET(3)/4);  
466         pReg = (uint32_t*)ddrVirt;   /* Now it points to the start of EDMA_TPCC0_BASE_ADDRESS */
468         while (true) {
469                 /* Use TC0 for DBS = 128 bytes */
470                 myIowrite32(0x0, pReg + DMAQNUM0/4);                
472                 /* Set the interrupt enable for 1st Channel (IER). */
473                 myIowrite32(0x1, pReg + IESR/4);
475                 /* Clear any pending interrupt (IPR). */
476                 myIowrite32(0x1, pReg + ICR/4);
478                 /* Populate the Param entry. */
479                 myIowrite32(0x00100004, pReg + PARAM_0_OPT/4);    /* Enable SYNCDIM and TCINTEN, TCC = 0 */
481                 if (flag == 1) {
482                         /* Calculate the DSP PCI address for the PC address */
483                         tmp = PCIE_DATA + (dstAddr & ~PCIE_1MB_BITMASK);
484                         myIowrite32(tmp, pReg + PARAM_0_DST/4);
485                 } else {
486                         myIowrite32(dstAddr, pReg + PARAM_0_DST/4);
487                 }
489                 /* Calculate the A & B count */
490                 if (size > PCIE_TRANSFER_SIZE)  {
491                         tmp = size/PCIE_TRANSFER_SIZE;
492                         tSize = tmp*PCIE_TRANSFER_SIZE;
493                         size -= (tmp*PCIE_TRANSFER_SIZE);
494                         tmp <<= 16;
495                         tmp |= PCIE_TRANSFER_SIZE;
496                 }
497                 else {
498                         tmp = 0x10000|size;
499                         tSize = size;
500                         size = 0;
501                 }
503                 myIowrite32(tmp, pReg + PARAM_0_A_B_CNT/4);
504                 myIowrite32(srcAddr, pReg + PARAM_0_SRC/4);
506                 myIowrite32(((PCIE_TRANSFER_SIZE<<16)|PCIE_TRANSFER_SIZE), pReg + PARAM_0_SRC_DST_BIDX/4);
507                 myIowrite32(0xFFFF, pReg + PARAM_0_LINK_BCNTRLD/4);
508                 myIowrite32(0x0, pReg + PARAM_0_SRC_DST_CIDX/4);
510                 /* C Count is set to 1 since mostly size will not be more than 1.75GB */
511                 myIowrite32(0x1, pReg + PARAM_0_CCNT/4);
513                 /* Set the Event Enable Set Register. */
514                 myIowrite32(0x1, pReg + EESR/4);
516                 /* Set the event set register. */
517                 myIowrite32(0x1, pReg + ESR/4);
519                 /* wait for current DMA to finish. */
520                 while (true) {
521                         /* check in steps of 10 usec. */
522                         udelay(10);
523                         tmp = myIoread32(pReg + IPR/4);
524                         if ((tmp & 0x1) == 1) {
525                                 break;
526                         }
527                 }
529                 if (size != 0) {
530                         srcAddr += tSize;
531                         dstAddr += tSize;
532                 } else {
533                         break;
534                 }
535         } 
537         /* Clear any pending interrupt. */
538         myIowrite32(1, pReg + ICR/4);
540         /* Restore pointer */
541         pReg = (uint32_t *)regVirt;     /* Point to PCIE application registers */
542         iowrite32(DDR_START, pReg + IB_OFFSET(3)/4); 
545 /* ============================================================================
546  *  @func   HAL_writeDMA
547  *
548  *  @desc   Move DMAs contents from GPP memory to DSP Memory. For DSP this is
549  *          outbound read.
550  *  flag:   0: Move data inside DSP; 1: Move data between GPP and DSP
551  *
552  *  @modif  None.
553  *  ============================================================================
554  */
555 void HAL_writeDMA(uint32_t srcAddr, uint32_t dstAddr, uint32_t size, uint32_t flag)
557         uint32_t *pReg, tmp, pageBase, i, tSize;
559         pReg = (uint32_t *)regVirt;     /* Point to PCIE application registers */
561         /* Move data between GPP and DSP, need to program PCIE OB registers */
562         if (flag) { 
563                 iowrite32(0x0, pReg + OB_SIZE/4); /* 1MB outbound translation size */
565                 if (size <= PCIE_ADLEN_1MB) {
566                         pageBase = srcAddr & PCIE_1MB_BITMASK;
567                         iowrite32(pageBase|0x1, pReg + OB_OFFSET_INDEX(0)/4);
568                         iowrite32(0x0, pReg + OB_OFFSET_HI(0)/4);  
569                 }
570                 else {
571                         for (tmp = size, i = 0; tmp > 0; tmp -= PCIE_ADLEN_1MB, i++) {
572                                 pageBase = (srcAddr + (PCIE_ADLEN_1MB * i)) & PCIE_1MB_BITMASK;
573                                 iowrite32(pageBase|0x1, pReg + OB_OFFSET_INDEX(i)/4);
574                                 iowrite32(0x0, pReg + OB_OFFSET_HI(i)/4);
575                         }
576                 }
577         }
579         /* Temporarily re-map IB region 3 from DDR memory to EDMA registers */
580         iowrite32(EDMA_TPCC0_BASE_ADDRESS, pReg + IB_OFFSET(3)/4);  
582         pReg = (uint32_t*)ddrVirt;   /* Now it points to the start of EDMA_TPCC0_BASE_ADDRESS */
584         while (true) {
585                 /* Use TC0 for DBS = 128 bytes */
586                 myIowrite32(0x0, pReg + DMAQNUM0/4);                
588                 /* Set the interrupt enable for 1st Channel (IER). */
589                 myIowrite32(0x1, pReg + IESR/4);
591                 /* Clear any pending interrupt (IPR). */
592                 myIowrite32(0x1, pReg + ICR/4);
594                 /* Populate the Param entry. */
595                 myIowrite32(0x00100004, pReg + PARAM_0_OPT/4);    /* Enable SYNCDIM and TCINTEN, TCC = 0 */
597                 if (flag == 1) {
598                         /* Calculate the DSP PCI address for the PC address */
599                         tmp = PCIE_DATA + (srcAddr & ~PCIE_1MB_BITMASK);
600                         myIowrite32(tmp, pReg + PARAM_0_SRC/4);
601                 } else {
602                         myIowrite32(srcAddr, pReg + PARAM_0_SRC/4);
603                 }
605                 /* Calculate the A & B count */
606                 if (size > PCIE_TRANSFER_SIZE)  {
607                         tmp = size/PCIE_TRANSFER_SIZE;
608                         tSize = tmp*PCIE_TRANSFER_SIZE;
609                         size -= (tmp*PCIE_TRANSFER_SIZE);
610                         tmp <<= 16;
611                         tmp |= PCIE_TRANSFER_SIZE;
612                 }
613                 else {
614                         tmp = 0x10000|size;
615                         tSize = size;
616                         size = 0;
617                 }
619                 myIowrite32(tmp, pReg + PARAM_0_A_B_CNT/4);
620                 myIowrite32(dstAddr, pReg + PARAM_0_DST/4);
622                 myIowrite32(((PCIE_TRANSFER_SIZE<<16)|PCIE_TRANSFER_SIZE), pReg + PARAM_0_SRC_DST_BIDX/4);
623                 myIowrite32(0xFFFF, pReg + PARAM_0_LINK_BCNTRLD/4);
624                 myIowrite32(0x0, pReg + PARAM_0_SRC_DST_CIDX/4);
626                 /* C Count is set to 1 since mostly size will not be more than 1.75GB */
627                 myIowrite32(0x1, pReg + PARAM_0_CCNT/4);
629                 /* Set the Event Enable Set Register. */
630                 myIowrite32(0x1, pReg + EESR/4);
632                 /* Set the event set register. */
633                 myIowrite32(0x1, pReg + ESR/4);
635                 /* wait for current DMA to finish. */
636                 while (true) {
637                         /* check in steps of 10 usec. */
638                         udelay(10);
639                         tmp = myIoread32(pReg + IPR/4);
640                         if ((tmp & 0x1) == 1) {
641                                 break;
642                         }
643                 }
645                 if (size != 0) {
646                         srcAddr += tSize;
647                         dstAddr += tSize;
648                 } else {
649                         break;
650                 }
651         } 
653         /* Clear any pending interrupt. */
654         myIowrite32(1, pReg + ICR/4);
656         /* Restore pointer */
657         pReg = (uint32_t *)regVirt;     //Point to PCIE application registers
658         iowrite32(DDR_START, pReg + IB_OFFSET(3)/4);  
661 /** ============================================================================
662  *  @func   ISR_handler
663  *
664  *  @desc   ISR.
665  *
666  *  @modif  None.
667  *  ============================================================================
668  */
669 static irqreturn_t ISR_handler(int irq, void *arg) 
671         uint32_t i, dma_failure_flag = 0, counter = 0;
672         uint32_t status = HAL_CheckPciInterrupt();
674         if (status == 1) {
675                 printk("Interrupt %d received from DSP\n", irq);
676                 printk("Read DMA from DSP ...\n");
677                 do_gettimeofday(&test_time3);
678                 HAL_readDMA(DDR_START, rData, DMA_TRANSFER_SIZE, 1);     /* Move from DSP to GPP */
679                 do_gettimeofday(&test_time4);
681                 for (i = 0; i < DMA_TRANSFER_SIZE; i++) {
682                         if ((~(rDataVirt[i])&0xFF) != wDataVirt[i]) {
683                                 dma_failure_flag = 1;
684                                 counter++;
685                         }
686                 }
688                 if (dma_failure_flag) 
689                         printk("DMA test failed with %d locations !\n", counter);
690                 else 
691                         printk("DMA test passed!\n");
693                 HAL_PciClearDspInterrupt();
694                 return IRQ_HANDLED;
695         }
696         return IRQ_NONE;
699 /* ============================================================================
700  *  @func   byteto32bits 
701  *
702  *  @desc   Convert 4 bytes to 32 bits long word
703  *
704  *  @modif  None.
705  *  ============================================================================
706  */
707 uint32_t byteTo32bits(uint8_t *pDspCode)
709         uint32_t i, temp;
711         temp = *pDspCode++;
712         for(i = 0; i < 3;i++) {
713                 temp <<= 8;
714                 temp |= *pDspCode++;
715         }
716         return(temp);
719 /* ============================================================================
720  *  @func   swap4bytes
721  *
722  *  @desc   Endian swap: 0xA0B1C2D3 to 0xD3C2B1A0 
723  *
724  *  @modif  None.
725  *  ============================================================================
726  */
727 void swap4bytes(uint32_t *pDspCode, uint32_t size)
729         uint32_t i, temp;
731         for(i = 0; i < size; i += 4, pDspCode++) {
732                 temp = *pDspCode;
733                 temp = (temp>>24) |
734                         ((temp<<8) & 0x00FF0000) |
735                         ((temp>>8) & 0x0000FF00) |
736                         (temp<<24);
738                 *pDspCode = temp;
739         }
742 /* ============================================================================
743  *  @func   writeDSPMemory
744  *
745  *  @desc   Write a block of data into DSP memory from Linux host. 
746  *          Note the data buffer is in 32-bit format, unit of length is byte. 
747  *          coreNum: to write data: 0-7 for cores 0-7; 8 for MSMC; 9 for DDR.
748  *
749  *  @modif  None.
750  *  ============================================================================
751  */
752 uint32_t writeDSPMemory(uint32_t coreNum, uint32_t DSPMemAddr, uint32_t *buffer, uint32_t length) 
754         uint32_t i, offset, tempReg = 0;
755         uint32_t *ptr;
757         if (length == 0) {
758                 return 0;
759         }
761         switch (coreNum) {
762 #if EVMC6678L
763                 case 0:
764                 case 1:
765                 case 2:
766                 case 3:
767                 case 4:
768                 case 5:
769                 case 6:
770                 case 7: 
771 #endif
772 #if EVMC6670L
773                 case 0:
774                 case 1:
775                 case 2:
776                 case 3:
777 #endif
778                         DSPMemAddr &= 0x00FFFFFF;
779                         tempReg = ioread32(ptrReg + IB_OFFSET(1)/4);
780                         iowrite32(tempReg + coreNum*0x01000000, ptrReg + IB_OFFSET(1)/4); /* pointing to a different core */
782                         if (DSPMemAddr < LL2_START) {
783                                 return 0;
784                         } else {  
785                                 offset = DSPMemAddr - LL2_START;
786                                 ptr = (uint32_t *)memVirt + offset/4;
787                         }
788                         break;
789                 case 8:  /* this is for MSMC */
790                         if (DSPMemAddr < MSMC_START) {
791                                 return 0;
792                         } else {
793                                 offset = DSPMemAddr - MSMC_START;
794                                 ptr = (uint32_t *)msmcVirt + offset/4;
795                         }               
796                         break;   
797                 case 9:  /* this is for DDR */
798                         if (DSPMemAddr < DDR_START) {
799                                 return 0;
800                         } else {  
801                                 offset = DSPMemAddr - DDR_START;
802                                 ptr = (uint32_t *)ddrVirt + offset/4;
803                         }
804                         break; 
805                 default:
806                         printk("Use coreNum 0-7 for core 0-7 of EVMC6678L, or coreNum 0-3 for core 0-3 of EVMC6670L; coreNum 8 for MSMC and coreNum 9 for DDR.\n");
807                         return 0;
808                         break;
809         }     
811         for (i = 0; i < length/4; i++) {
812 #if BIG_ENDIAN
813                 swap4bytes(&buffer[i], 4);
814 #endif
815                 *ptr = buffer[i];
816                 ptr++; 
817         }
819         if ((coreNum >= 0)&&(coreNum <= 7)) {
820                 iowrite32(tempReg, ptrReg + IB_OFFSET(1)/4);  /* Restore IB_OFFSET1 */
821         }
823         return length;
826 /* ============================================================================
827  *  @func   readDSPMemory
828  *
829  *  @desc   Read a block of DSP memory by Linux host. 
830  *          Note the data buffer is in 32-bit format, unit of length is byte. 
831  *          coreNum: to read data: 0-7 for cores 0-7; 8 for MSMC; 9 for DDR.
832  *
833  *  @modif  None.
834  *  ============================================================================
835  */
836 uint32_t readDSPMemory(uint32_t coreNum, uint32_t DSPMemAddr, uint32_t *buffer, uint32_t length) 
838         uint32_t i, offset, tempReg = 0;
839         uint32_t *ptr;
841         if (length == 0) {
842                 return 0;
843         }  
845         switch (coreNum) {
846 #if EVMC6678L
847                 case 0:
848                 case 1:
849                 case 2:
850                 case 3:
851                 case 4:
852                 case 5:
853                 case 6:
854                 case 7: 
855 #endif
856 #if EVMC6670L
857                 case 0:
858                 case 1:
859                 case 2:
860                 case 3:
861 #endif
862                         DSPMemAddr &= 0x00FFFFFF;
863                         tempReg = ioread32(ptrReg + IB_OFFSET(1)/4);
864                         iowrite32(tempReg + coreNum*0x1000000, ptrReg + IB_OFFSET(1)/4);        /* pointing to a different core */
865                         if (DSPMemAddr < LL2_START) {
866                                 return 0;
867                         } else {  
868                                 offset = DSPMemAddr - LL2_START;
869                                 ptr = (uint32_t *)memVirt + offset/4;
870                         }
871                         break;
872                 case 8:  /* this is for MSMC */
873                         if (DSPMemAddr < MSMC_START) {
874                                 return 0;
875                         } else {                   
876                                 offset = DSPMemAddr - MSMC_START;
877                                 ptr = (uint32_t *)msmcVirt + offset/4;
878                         }
879                         break;   
880                 case 9:  /* this is for DDR */
881                         if (DSPMemAddr < DDR_START) {
882                                 return 0;
883                         } else {                   
884                                 offset = DSPMemAddr - DDR_START;
885                                 ptr = (uint32_t *)ddrVirt + offset/4;
886                         }
887                         break; 
888                 default:
889                         printk("Use coreNum 0-7 for core 0-7 of EVMC6678L, or coreNum 0-3 for core 0-3 of EVMC6670L; coreNum 8 for MSMC and coreNum 9 for DDR.\n");
890                         return 0;
891                         break;
892         }     
894         for (i = 0; i < length/4; i++) {
895                 buffer[i] = *ptr;
896 #if BIG_ENDIAN
897                 swap4bytes(&buffer[i], 4);
898 #endif
899                 ptr++;
900         }
902         if ((coreNum >= 0)&&(coreNum <= 7)) {
903                 iowrite32(tempReg, ptrReg + IB_OFFSET(1)/4);  /* Restore IB_OFFSET1 */
904         }
906         return length;
909 /* ============================================================================
910  *  @func   pushData
911  *
912  *  @desc   Parser function for DSP boot image array
913  *
914  *  @modif  None.
915  *  ============================================================================
916  */
917 void pushData(uint8_t *pDspCode, uint8_t coreNum, uint32_t *bootEntryAddr)
919         uint32_t i, j, tempArray[BLOCK_TRANSFER_SIZE/4];
920         uint32_t size, section = 0, totalSize = 0;
921         uint32_t count, remainder, startaddr;
923         /* Get the boot entry address */
924         *bootEntryAddr = byteTo32bits(pDspCode);
925         printk("Boot entry address is 0x%8x\n", *bootEntryAddr);
926         pDspCode +=4;
928         while(1) {
930                 /* Get the size */
931                 size = byteTo32bits(pDspCode);
932                 if(size == 0) break;
934                 if ((size/4)*4 != size) {
935                         size = ((size/4)+1)*4;
936                 }
938                 totalSize += size;
939                 section++;
940                 pDspCode += 4;
941                 startaddr = byteTo32bits(pDspCode);
943                 pDspCode+= 4;
945                 count = size/BLOCK_TRANSFER_SIZE;
947                 remainder = size - count * BLOCK_TRANSFER_SIZE;
949                 for(i = 0; i < count; i++) {
950                         for (j = 0; j < BLOCK_TRANSFER_SIZE/4; j++) {
951                                 tempArray[j] = byteTo32bits(pDspCode);
952                                 pDspCode += 4;
953                         }
954                         /* Transfer boot tables to DSP */
955                         writeDSPMemory(coreNum, startaddr, tempArray, BLOCK_TRANSFER_SIZE); 
956                         startaddr += BLOCK_TRANSFER_SIZE;
957                 }
959                 for (j = 0; j < remainder/4; j++) {
960                         tempArray[j] = byteTo32bits(pDspCode);
961                         pDspCode += 4;
962                 }
963                 writeDSPMemory(coreNum, startaddr, tempArray, remainder); 
964         }
965         printk("Total %d sections, 0x%x bytes of data written to core %d\n", section, totalSize, coreNum);
968 /* ============================================================================
969  *  @func   init_module
970  *
971  *  @desc   Initialize a loadable module 
972  *
973  *  @modif  None.
974  *  ============================================================================
975  */
976 int init_module(void)
978         uint32_t i; 
979         uint32_t bootEntryAddr = 0;              /* Store 32-bit boot entry address read from .h file */
980 #if HELLO_WORLD_DEMO | EDMA_INTC_DEMO
981         uint32_t buffer[BLOCK_TRANSFER_SIZE/4];  /* Store 32-bit DSP memory readback data */
982 #endif 
984 #if EDMA_INTC_DEMO
985         uint32_t diff;
986 #endif
988         printk ("Finding the device....\n") ;
989         PCI_FindPciDevices();
990         if (!PCIE_DEV) {
991                 printk ("No PCIE device found!!!\n") ;
992         }
994         if (PCIE_DEV != NULL) {
996                 printk("Reading the BAR areas....\n");
997                 PCI_readBAR();
999                 printk("Enabling the device....\n");
1000                 /* Linux Function: Initialize device before it's used by a driver */
1001                 pci_enable_device(PCIE_DEV);
1003                 /* Linux Function: Associates the given data with the given pci_driver structure */
1004                 pci_set_drvdata(PCIE_DEV, memVirt);
1006                 PCI_setMaster();
1008                 printk("Access PCIE application register ....\n");
1009                 /* Pointing to the beginning of the application registers */
1010                 ptrReg = (uint32_t *)regVirt;
1012                 /* Configure IB_BAR0 to BAR0 for PCIE registers; Configure IB_BAR1 to BAR1 for LL2 for core 0
1013                    Configure IB_BAR2 to BAR2 for MSMC; Configure IB_BAR3 to BAR3 for DDR */
1014                 for (i = 0; i < 4; i++) {
1015                         iowrite32(i, ptrReg + IB_BAR(i)/4);     
1016                         iowrite32(PCIE_DEV->resource[i].start, ptrReg + IB_START_LO(i)/4);    
1017                         iowrite32(0, ptrReg + IB_START_HI(i)/4);
1018                 }     
1019                 iowrite32(PCIE_BASE_ADDRESS, ptrReg + IB_OFFSET(0)/4);    
1020                 iowrite32(LL2_START + (1 << 28), ptrReg + IB_OFFSET(1)/4);    
1021                 iowrite32(MSMC_START, ptrReg + IB_OFFSET(2)/4);  
1022                 iowrite32(DDR_START, ptrReg + IB_OFFSET(3)/4); 
1024                 printk("Registering the irq %d ...\n", irqNo);
1025                 request_irq(irqNo, ISR_handler, IRQF_SHARED, "TI 667x PCIE", &dummy);
1026                 HAL_PciEnableDspInterrupt();
1028 #if HELLO_WORLD_DEMO
1029                 /* Load DDR init code into DSP */
1030                 pushData(ddrInitCode, 0, &bootEntryAddr);
1032                 /* Write boot entry address into MAGIC_ADDR */
1033                 writeDSPMemory(0, MAGIC_ADDR, &bootEntryAddr, 4);       
1035                 while (1) {
1036                         readDSPMemory(0, MAGIC_ADDR, buffer, 4);
1037                         if (buffer[0] == 0)  break;
1038                         for (i = 0; i < 1000; i++) i++;
1039                 } 
1041                 /* Load "Hello World" demo into DSP */
1042                 pushData(bootCode, 9, &bootEntryAddr);
1044                 /* Write boot entry address into MAGIC_ADDR */
1045                 writeDSPMemory(0, MAGIC_ADDR, &bootEntryAddr, 4);
1046 #endif
1048 #if POST_DEMO
1049                 /* Load POST demo code into DSP */
1050                 pushData(post, 0, &bootEntryAddr);
1052                 /* Write boot entry address into MAGIC_ADDR */
1053                 writeDSPMemory(0, MAGIC_ADDR, &bootEntryAddr, 4);       
1054 #endif
1056 #if EDMA_INTC_DEMO
1058                 printk("Allocating consistent memory ...\n"); 
1059                 wDataVirt = (uint8_t*)dma_alloc_coherent(&PCIE_DEV->dev, DMA_TRANSFER_SIZE, &wData, GFP_KERNEL);
1060                 rDataVirt = (uint8_t*)dma_alloc_coherent(&PCIE_DEV->dev, DMA_TRANSFER_SIZE, &rData, GFP_KERNEL);
1062                 for (i = 0; i < DMA_TRANSFER_SIZE; i++) {
1063                         wDataVirt[i] = i;
1064                         rDataVirt[i] = 0;
1065                 }
1067                 /* Load Interrupt demo code into DSP */
1068                 pushData(pcieInterrupt, 0, &bootEntryAddr);
1070                 /* Write boot entry address into MAGIC_ADDR */
1071                 writeDSPMemory(0, MAGIC_ADDR, &bootEntryAddr, 4);       
1073                 while (1) {
1074                         readDSPMemory(0, MAGIC_ADDR, buffer, 4);
1075                         if (buffer[0] == 0)  break;
1076                         for (i = 0; i < 1000; i++) i++;
1077                 } 
1079                 /* Wait 2 second for DDR init */
1080                 mdelay(2000);
1082                 printk ("Write DMA to DSP ...\n");
1083                 do_gettimeofday(&test_time1);
1084                 HAL_writeDMA (wData, DDR_START, DMA_TRANSFER_SIZE, 1);   /* Move from GPP to DSP */ 
1085                 do_gettimeofday(&test_time2);
1087                 /* Note: From PCIE specification, legacy interrupts cannot be generated from RC and be passed downstream. 
1088                    The example below is just making use of the facility that RC can access EP side register to generate 
1089                    a generic interrupt on local (EP) side using one of the event inputs of Interrupt Controller (INTC). 
1090                    There is no real interrupt signal sent over the PCIe link */
1091                 printk ("Generating interrupt to DSP ...\n");
1092                 iowrite32(1, ptrReg + LEGACY_A_IRQ_STATUS_RAW/4); 
1094                 /* Waiting DSP ISR handler to process the interrupt from DSP and then generates an interrupt to host
1095                    Waiting for host ISR handler to process the interrupt from DSP before program exits */ 
1096                 mdelay(1000);
1098                 /* For demo how to move inside DSP purpose only, you can directly move between GPP and DSP using flag = 1 */
1099                 //      HAL_writeDMA (0x80000000, 0x11800000, 0x10000, 0);        
1100                 //      HAL_writeDMA (0x11800000, 0x0C000000, 0x10000, 0);
1102                 diff = (test_time2.tv_sec - test_time1.tv_sec)*1000000 + (test_time2.tv_usec - test_time1.tv_usec);
1103                 printk("DMA write throughput is: %d.%02d MB/s\n", DMA_TRANSFER_SIZE/(1024*1024)*1000*1000/diff, 
1104                                 ((DMA_TRANSFER_SIZE/(1024*1024)*1000*1000)%diff)*100/diff);
1106                 diff = (test_time4.tv_sec - test_time3.tv_sec)*1000000 + (test_time4.tv_usec - test_time3.tv_usec);
1107                 printk("DMA read throughput is: %d.%02d MB/s\n", DMA_TRANSFER_SIZE/(1024*1024)*1000*1000/diff, 
1108                                 ((DMA_TRANSFER_SIZE/(1024*1024)*1000*1000)%diff)*100/diff);
1110                 printk("Freeing consistent memory ...\n");
1111                 dma_free_coherent(&PCIE_DEV->dev, DMA_TRANSFER_SIZE, wDataVirt, wData);
1112                 dma_free_coherent(&PCIE_DEV->dev, DMA_TRANSFER_SIZE, rDataVirt, rData);
1113 #endif
1114         }
1115         else {
1116                 printk("No PCIE device found!!!\n");
1117         }
1118         return 0 ;
1121 /* ============================================================================
1122  *  @func   cleanup_module
1123  *
1124  *  @desc   Unregister a loadable module 
1125  *
1126  *  @modif  None.
1127  *  ============================================================================
1128  */
1130 void cleanup_module(void)
1133         if (PCIE_DEV != NULL) {
1134                 HAL_PciDisableDspInterrupt();
1135                 /* ---------------------------------------------------------------------
1136                  * Unmap baseRegs region & release the reg region.
1137                  * ---------------------------------------------------------------------
1138                  */
1139                 iounmap(regVirt);
1140                 if (pci_resource_flags(PCIE_DEV, 0) & IORESOURCE_MEM) {
1141                         /* Map the memory region. */
1142                         release_mem_region(regBase, regLen);
1143                 }
1144                 else {
1145                         /* Map the memory region. */
1146                         release_region(regBase, regLen);
1147                 }
1149                 /* ---------------------------------------------------------------------
1150                  * Unmap LL2 region & release the reg region.
1151                  * ---------------------------------------------------------------------
1152                  */
1153                 iounmap(memVirt);
1154                 if (pci_resource_flags(PCIE_DEV, 1) & IORESOURCE_MEM) {
1155                         /* Map the memory region. */
1156                         release_mem_region(memBase, memLen);
1157                 }
1158                 else {
1159                         /* Map the memory region. */
1160                         release_region(memBase, memLen);
1161                 }
1163                 /* ---------------------------------------------------------------------
1164                  * Unmap MSMC region & release the reg region.
1165                  * ---------------------------------------------------------------------
1166                  */
1167                 iounmap(msmcVirt);
1168                 if (pci_resource_flags(PCIE_DEV, 2) & IORESOURCE_MEM) {
1169                         /* Map the memory region. */
1170                         release_mem_region(msmcBase, msmcLen);
1171                 }
1172                 else {
1173                         /* Map the memory region. */
1174                         release_region(msmcBase, msmcLen);
1175                 }
1177                 /* ---------------------------------------------------------------------
1178                  * Unmap DDR region & release the reg region.
1179                  * ---------------------------------------------------------------------
1180                  */
1181                 iounmap(ddrVirt);
1182                 if (pci_resource_flags(PCIE_DEV, 3) & IORESOURCE_MEM) {
1183                         /* Map the memory region. */
1184                         release_mem_region(ddrBase, ddrLen);
1185                 }
1186                 else {
1187                         /* Map the memory region. */
1188                         release_region(ddrBase, ddrLen);
1189                 }
1191                 free_irq(irqNo, &dummy);
1192         }