2360d14199bb410b767130b660ec989b06e487c6
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)
214 {
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 }
227 }
229 /* ============================================================================
230 * @func PCI_readBAR
231 *
232 * @desc This function reads config.
233 *
234 * @modif None.
235 * ============================================================================
236 */
237 void PCI_readBAR(void)
238 {
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];
333 }
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)
344 {
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);
370 }
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)
381 {
382 uint32_t *pReg = (uint32_t *)regVirt;
383 return ioread32(pReg + EP_IRQ_STATUS/4);
384 }
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)
395 {
396 uint32_t *pReg = (uint32_t *)regVirt;
397 iowrite32(1, pReg+EP_IRQ_CLR/4);
398 }
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)
409 {
410 uint32_t *pReg = (uint32_t *)regVirt;
411 iowrite32(1, pReg+LEGACY_A_IRQ_ENABLE_SET/4);
412 }
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)
423 {
424 uint32_t *pReg = (uint32_t *)regVirt;
425 iowrite32(1, pReg+LEGACY_A_IRQ_ENABLE_CLR/4);
426 }
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)
440 {
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);
543 }
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)
556 {
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);
659 }
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)
670 {
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;
697 }
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)
708 {
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);
717 }
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)
728 {
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 }
740 }
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)
753 {
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;
824 }
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)
837 {
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;
907 }
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)
918 {
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);
966 }
968 /* ============================================================================
969 * @func init_module
970 *
971 * @desc Initialize a loadable module
972 *
973 * @modif None.
974 * ============================================================================
975 */
976 int init_module(void)
977 {
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 ;
1119 }
1121 /* ============================================================================
1122 * @func cleanup_module
1123 *
1124 * @desc Unregister a loadable module
1125 *
1126 * @modif None.
1127 * ============================================================================
1128 */
1130 void cleanup_module(void)
1131 {
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 }
1193 }