Hello,I am working on a DM814x chip and I have encounter a problem. Hopping anyone have found solutions....:-)
We need to access the GPMC bus from the C674x directly but unfortunately the GPMC memory is not mapped to the C674x core.We could not read the data through the ARM and pass it to the DSP because of real time issues (linux latencies).It seems I must pass through the DSP MMU that mapped L3 regions.
My 3 questions are:
1/ How can I access the GPMC memory space from the C674x without using DMA? Which MMU register should I configure.
2/ How can I access the GPMC memory space from the C674x using DMA? How to configure the DMA access.
3/ How does the DSP access to the DDR space? is it also from the MMU?
Thanks for any help
Jonathan,
DSP has to go thru the (DE)MMU to access GPMC.
EDMA can access GPMC directly or via (DE)MMU.
You will find the connectivity details in the DM814x DS (Sept. 2011) table 5-1.
Rgds,
Viet
We also have the same issue. We have the GPMC bus bridged to the NIOS Avalon bus so we can extend the SOC but we need the DSP to access the NIOS fabric as well. Also we need to use the video port as a way to upload video data directly to the DSP. Does the HDVPSS need to be controlled by the ARM as well. That would also add in Linux delays.
Hi Viet,
Well, I have successfully access the GPMC bus through the EDMA via the DSP core, the EDMA accessed the GPMC directly.
You wrote that each DSP and EDMA could also access the GPMC peripheral via the (DE) MMU.
How can it be done?
What do I need to configure to make it possible, may be it is the MMU_RAM register and other MMU registers?
If yes, is there any reference code initialization that may be shared?
thanks,
About DSP access to the NIOS memory through PCI, It can be done via EDMA like I did for the GPMC memory.
All 674x cores define 0x0080_0000 as L2 RAM and similarly they define other low addresses as L1 RAM, configuration registers, etc. That's why the 674x has trouble accessing the GPMC address range which resides at address 0x00000000 on the L3 Interconnect. To get around this issue you configure the System MMU such that it maps some other address range (e.g. 0x1100_0000) to map to address 0x00000000. By creating this mapping in the MMU you can perform a 674x access to 0x1100_0000 and have the MMU translate that access to 0x00000000 on the L3 interconnect. Hopefully that makes sense at a high level.
The actual mechanics of programming this virtual to physical address translation can be found in the Section "MMU Low-Level Programming Models" of the TRM. For "quick and easy" programming you likely will want to simply use a static TLB programming as the complexity goes up once you enable Table Walking inside the MMU. The details for programming a static TLB entry are documented in Table 1-49. "MMU Writing TLB Entries Statically".
Best regards,Brad
---------------------------------------------------------------------------------------------------------
Please click the Verify Answer button on this post if it answers your question.---------------------------------------------------------------------------------------------------------
Thanks Brad for your precious answer.
I'll try it and report.
If anyone has a code example of MMU configuration, I'll be happy to have a look on it.
Did this work and is there any code example?
Can this be done in a GEL script (initially) ?
We have the same issue and it seems like the remapping could be the same for everyone.
I have same problem. I wish somebody can give me advices how to access the GPMC bus through the EDMA via the DSP core.
Thanks in advanced,
David
Here is what I have learned, our board is now working.
When the DSP tries to access any unmapped address, the core will hang. The Linux console will produce an error message starting with "irq 122...". If you built the IOMMU debug driver, you can install it and print out the registers ("cat regs"). The FAULT_AD register contains the address that caused the fault. If it is an address you need to access, add it to your mapping. The registers shown here are the same ones the DSP sees at 0x0801_0000 (when the core is not hung).
Below is the code that got our board working. It makes the 0x0100_0000 address appear to the DSP at 0x1100_0000. It is based on the sequence given in the TRM. Just call configureMmu() early in main() before starting BIOS
/*----------------------------------------------------------------------------- Purpose: Writes a single TLB entry into the MMU-- Inputs: entry number- virtual address (as seen from DSP)- physical address (as seen from ARM)-- Notes: Assumes a super section 16 MB size (0x0100_0000)----------------------------------------------------------------------------*/Void mmuWriteStaticTlb(int entry, unsigned long va, unsigned long pa){const int MMU_BASE = 0x08010000;volatile int *mmu_lock = ( int *)(MMU_BASE + 0x50);volatile int *mmu_ld_tlb = ( int *)(MMU_BASE + 0x54);volatile int *mmu_cam = ( int *)(MMU_BASE + 0x58);volatile int *mmu_ram = ( int *)(MMU_BASE + 0x5c);// configure TLB virtual address , 16 MB super-section, protect, validate*mmu_cam = (va & 0xfff00000) | 0x0000000f;// load physical address of the page*mmu_ram = (pa & 0xfff00000);// lock from base value 0*mmu_lock = ((entry + 1) << 10) | (entry << 4);// load the specified entry in the TLB*mmu_ld_tlb = 0x00000001;}/*----------------------------------------------------------------------------- Purpose: Configures the MMU for all access to external memory-- Notes: Required for access to the GPMC bus- See spprugz8 Figure 1-22 MMU Global Initialization & table 1-50----------------------------------------------------------------------------*/Void configureMmu(){const int MMU_BASE = 0x08010000;volatile int *mmu_revision = ( int *)(MMU_BASE + 0x00);volatile int *mmu_sysconfig = ( int *)(MMU_BASE + 0x10);volatile int *mmu_sysstatus = ( int *)(MMU_BASE + 0x14);volatile int *mmu_irqenable = ( int *)(MMU_BASE + 0x1c);volatile int *mmu_cntl = ( int *)(MMU_BASE + 0x44);int entry = 0;System_printf("Configuring MMU revision = 0x%08x\n", *mmu_revision); System_flush();// execute SW reset*mmu_sysconfig = 0x00000002;// wait for resetwhile ((*mmu_sysstatus & 0x00000001) != 0);// enable power save//*mmu_sysconfig = 0x00000001; crashes with this line// configure 16 16-MB segments of DDR for straight throughfor (entry = 0; entry < 16; entry++){mmuWriteStaticTlb(entry, 0x80000000 | (entry << 24), 0x80000000 | (entry << 24));}// registersmmuWriteStaticTlb(entry, 0x40000000, 0x40000000);entry++;// GPMCmmuWriteStaticTlb(entry, 0x11000000, 0x01000000);entry++;// DDR control (cache control by syslink)mmuWriteStaticTlb(entry, 0x4c000000, 0x4c000000);entry++;// enable multihit fault and TLB miss*mmu_irqenable = 0x00000011;// enable memory translations (turn it on)*mmu_cntl = 0x00000002;// if this prints, at least the DDR mapping is workingSystem_printf("MMU configured\n"); System_flush();}
David,
Thanks for sharing this info with the community. I have some follow-up info regarding the points you mentioned.
David JonesWhen searching for information, there seem to be many names for the same peripheral. These include MMU, DSP/EDMA MMU, DEMMU, IOMMU, system MMU and probably others.
David JonesThe best documentation is the errata sheet, but the table "MMU entries" is not correct. The code is a good example of setting up the TLB entries.
In the data manual we will replace all occurrences of "DSP/EDMA MMU" with "System MMU". In the errata we will replace the term "DEMMU" with "System MMU" to be consistent with the TRM. I have added a note in the PSP User's Guide and the PSP IOMMU Driver Guide stating that IOMMU is the same as System MMU.
The MMU entries description in the errata should be as follows:
We will update the errata accordingly.
David JonesIf you map the GPMC, you must map everything. Once you turn the MMU on, everything is blocked except what is mapped.
As a side note I want to make it clear to others that by "everything" that means "every memory block the DSP is supposed to be accessing". So in typical scenario you would not want to map the entire DDR memory space. Most of the DDR memory space should be exclusively used by the ARM and so by not mapping these addresses you provide an additional safety net should the DSP accidentally access a place it's not supposed to. That way instead of crashing the ARM you end up with a System MMU fault which will effectively hang the DSP and provide information with respect to what address was improperly accessed, etc.
Hello,
I am trying to configure the System MMU to access the DSP non-mapped memory (GPMC memory) from the DSP core.
But when accessing the RAM from the DSP apps, the core hangs. (beacaus of a mmu exception)
My DSP system memory setup is :
MEMORY CONFIGURATION
name origin length used unused attr fill
---------------------- -------- --------- -------- -------- ---- --------
SHMEM_DATA 91a00000 03f00000 028f5660 0160a9a0 RW X
SHMEM_CFG 95900000 00100000 0000bad0 000f4530 RW X
DDR3_DSP 95a00000 01000000 00380a3a 00c7f5c6 RW X
SR0 9f700000 00200000 00200000 00000000 RW X
SR1 9f900000 00c00000 00c00000 00000000 RW X
All that memory is used by the DSP for code / data / syslink
I modified the System MMU Init code, generously provided by David Jones, so I mapped the Physical memory use by my DSP apps (0x91000000 – to 0xA1000000 . 16* 16 MB).
It seems the MMU mapping covers all the DDR memory. But when running the DSP application.
The DSP core hangs, the ARM signals a iommu_fault exception. And reading the MMU FAULT REGISTER tells us that the fault occurs because a read at address 0x95d3f1000 , that is the first C function called from the main program just after I have called the Init MMU function.
I'll be pleased to know if I did something wrong in the MMU Initialization. (for know I removed the GPMC mapping and the GPMC reads from the DSP apps)
Thanks,
Here is the modified Init section:
// System_printf("Configuring MMU revision = 0x%08x\n", *mmu_revision); System_flush();
// execute SW reset
*mmu_sysconfig = 0x00000002;
// wait for reset
while ((*mmu_sysstatus & 0x00000001) != 0);
// enable power save
//*mmu_sysconfig = 0x00000001; crashes with this line
// configure 16 16-MB segments of DDR for straight through
for (entry = 0; entry < 16; entry++)
{
mmuWriteStaticTlb(entry, 0x91000000 | (entry << 24), 0x91000000 | (entry << 24));
}
// registers
mmuWriteStaticTlb(entry, 0x40000000, 0x40000000);
entry++;
// GPMC
// mmuWriteStaticTlb(entry, 0x11000000, 0x1f000000);
// entry++;
// DDR control (cache control by syslink)
mmuWriteStaticTlb(entry, 0x4c000000, 0x4c000000);
// enable multihit fault and TLB miss
*mmu_irqenable = 0x00000011;
// enable memory translations (turn it on)
*mmu_cntl = 0x00000002;
// if this prints, at least the DDR mapping is working
// System_printf("MMU configured\n"); System_flush();
Hi Jonathan,
A page that might be helpful related to DSP MMU faults is this one:
http://processors.wiki.ti.com/index.php/DSP_MMU_Faults
It was written around Codec Engine and DSPLink, but the underlying details in terms of the root cause of various issues remains the same.
Jonathan JournoThe DSP core hangs, the ARM signals a iommu_fault exception. And reading the MMU FAULT REGISTER tells us that the fault occurs because a read at address 0x95d3f1000 , that is the first C function called from the main program just after I have called the Init MMU function.
What is the value of the MMU_IRQSTATUS register? (This is along the lines of how we debug issues in the wiki page I referenced.) I have a suspicion that you're running into MMU_IRQSTATUS = 0x10 (Multi-Hit Fault).
Jonathan Journo for (entry = 0; entry < 16; entry++) { mmuWriteStaticTlb(entry, 0x91000000 | (entry << 24), 0x91000000 | (entry << 24)); }
I think your math is incorrect. I think you should be doing (0x91000000 | (entry << 24)) + 0x01000000.
The iommu driver on the arm that lets you verify the TLB entries and read the registers. On our distribution it must be built as a module or the build crashes. An example of calling it is below.
// install iommu debug driverinsmod /lib/modules/2.6.37-ts-armv7l/kernel/arch/arm/plat-omap/iommu-debug.komount -t debugfs none /sys/kernel/debug/cd /sys/kernel/debug/iommu/syscat regscat tlb
Output:
REVISION: 00000020 SYSCONFIG: 00000000 SYSSTATUS: 00000000 IRQSTATUS: 00000001 IRQENABLE: 00000011 WALKING_ST: 00000000 CNTL: 00000002 FAULT_AD: 50000060 TTB: 00000000 LOCK: 00005550 LD_TLB: 00000000 CAM: fff0000c RAM: fff00000 GFLUSH: 00000000 FLUSH_ENTRY: 00000000 READ_CAM: 00000000 READ_RAM: 00000000 EMU_FAULT_AD: 00000000
cam: ram:-----------------------------------------1000000f 00000000 11100000f 01000000 10200000e 12000000 14c00000e 4c000000 18000000f 80000000 18100000f 81000000 18200000f 82000000 18300000f 83000000 18400000f 84000000 18500000f 85000000 18600000f 86000000 18700000f 87000000 18800000f 88000000 18900000f 89000000 18a00000f 8a000000 18b00000f 8b000000 18c00000f 8c000000 18d00000f 8d000000 18e00000f 8e000000 18f00000f 8f000000 1fff0000c fff00000 1
Thanks Brad.
you're right, the math was a "bit" fishy. :-)
the DSP core now uses the MMU for accessing the RAM and also the GPMC bus.
Thanks a lot for your support.
Jonathan