05-08-2014 11:42 AM
There's a couple of questions about VDMA.
In my project, I'm using VDMA IP configured as a frame buffer. In standalone applications I have no problems allocating a part of memory for it and this part of memory never overlaps the part of memory my application uses. In Linux application I find a virtual base address of VDMA using /dev/mem and the mmap function.
But how do I tell the operational system not to use the part of physical memory belonging to frame buffer?
Or how do I allocate memory for frame buffer in physical memory?
I've examined XAPP794 reference design, and in this design the range 0x0 - 0x4000000 is allocated for DDR. This range is also written in .dts file. But in Linux application the start address of the first frame of the frame buffer is 0x3000000. So how does this work? How Linux knows that it cannot use memory with addresses higher than 0x3000000?
Thank you very mush in advance.
05-08-2014 12:07 PM - edited 05-08-2014 12:10 PM
You can use the memmap kernel argument
memmap=nn[KMG]$ss[KMG] [KNL,ACPI] Mark specific memory as reserved. Region of memory to be reserved is from ss to ss+nn. Example: Exclude memory from 0x18690000-0x1869ffff memmap=64K$0x18690000 or memmap=0x10000$0x18690000
05-09-2014 08:01 AM
05-11-2014 02:19 AM
I wouldn't like to use kernel space drivers and I have no necessity of allocating mamory for frame buffer dynamically. I'd like to tune VDMA just like it is done in XAPP794 reference design. In this design it is tuned through direct writing to registers:
#define VDMA_VITA_MEM_BASE_ADDR 0x30000000
fd = open("/dev/mem", O_RDWR);
map_CoreAddress = (Xuint32)mmap(NULL, VIDEO_MMAP_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)XPAR_AXI_VDMA_1_BASEADDR );
uBaseAddr = map_CoreAddress;
frameAddress1 = VDMA_VITA_MEM_BASE_ADDR + (frame_size * 0);
frameAddress2 = VDMA_VITA_MEM_BASE_ADDR + (frame_size * 1);
frameAddress3 = VDMA_VITA_MEM_BASE_ADDR + (frame_size * 2);
*((volatile int *)(uBaseAddr+XAXIVDMA_S2MM_ADDR_OFFSET+XAXIVDMA_START_ADDR_OFFSET+0)) = frameAddress1; //0x30000000; // DDR starting address of frame buffer-0
*((volatile int *)(uBaseAddr+XAXIVDMA_S2MM_ADDR_OFFSET+XAXIVDMA_START_ADDR_OFFSET+4)) = frameAddress2; //0x30870000; // DDR starting address of frame buffer-1
*((volatile int *)(uBaseAddr+XAXIVDMA_S2MM_ADDR_OFFSET+XAXIVDMA_START_ADDR_OFFSET+8)) = frameAddress3; //0x310E0000; // DDR starting address of frame buffer-2
так же в этом референс дизайне есть функция котороя позволяет инециалезировать фрэйм буфер картинкой bmp:
physicalAddress = VDMA_VITA_MEM_BASE_ADDR;
physicalSize = 3*0x870000*sizeof(unsigned int);
// Map physical frame buffer address to virtual space
fd_mmap = open("/dev/mem", O_RDWR);
virtualAddress = (Xuint32)mmap(NULL, physicalSize,
PROT_READ | PROT_WRITE, MAP_SHARED, fd_mmap, (off_t)physicalAddress );
for ( frameIdx = 0; frameIdx < 3; frameIdx++ )
frameAddress = virtualAddress + frameIdx*0x870000;
// Open BMP file
fd_bmp = open(cargv, O_RDONLY);
close( fd_bmp );
} // for ( frameIdx = 0; frameIdx < 3; frameIdx++ )
// Unmap frame buffer address
Also I want to have an opportunity to write a picture to frame buffer. I think using memmap will not allow to do this. Besides, memmap is not used in XAPP794.
I do not understand neither how access to frame buffer memory is restricted in XAPP794 nor do I have to do this at all.
How do I restrict the access so that I have an opportunity of writing a picture to frame buffer?
05-11-2014 01:26 PM
you might find this interesting
I can't get it to compile. Be curious if you get what you're trying to do to work. I also tried the memmap suggestion above and that didn't work.
05-12-2014 05:09 AM
Well, I gave you the correct answer to your questions. Any skilled C programmer should be able to combine that into a working driver in a few days. An experienced kernel programmer should be able to do it in less than a day.
Since you'd rather hack around, okay, here's the dirty way to do it:
- Change the devicetree of your kernel and alter the "memory" parameter, so that your memory range is no longer part of the normal RAM.
- Add the SIMPLEFB driver to your kernel through the menuconfig. Add the memory address, range, width height and stride parameters of your framebuffer to the configuration setting in the devicetree.
- Install this on your system, and you should now have a working /dev/fb0 that can be mmapped like any framebuffer.
(You can also contact my company topic.nl, we've built drivers for other customers too.)
05-12-2014 08:10 AM
I agree that is the correct answer. My major challenge is that is for one core. The problem I'm running into, particulary for designs with a long image processing pipeline, how do I reuse the existing SDK libsrc IP that Xilinx provides for controlling their cores from software? That is, if I have a axi scaler before the frame buffer how do I control it?
Do I need to write a driver for each PL core even though they'll often have no direct interaction with Linux besides configuration?
05-13-2014 03:12 AM
For a configuration only interface there's a generic Linux UIO driver that you can use to interface with memory mapping and even simple user-space IRQ handling. This takes the hardware addressing and conversion away from your application and places it into the devicetree configuration.
For standard devices like a framebuffer, applications expect it to have a certain interface (i.e. a memory mappable /dev/fb0 node). You can go two ways here. Either write a driver (which in the case of a flat memory is less than a day's work) that controls the logic and makes it into something that userspace expects. The alternative is to make the logic have a well-known interface. You can use the "simplefb" driver if you place the buffer at a fixed location and reserve that memory. Alternatively, you can make your logic to resemble a standard existing card, and then use the driver for that card to control it.
It just depends on where your skills and interests are. Sometimes it's less work to create a Linux driver for a custom UART in logic, and sometimes is more convenient to just emulate a 16550 in logic and use the standard driver.
08-29-2014 12:48 PM
This approach works, but at the expense of performance. You can do a mmap on a region of /dev/mem that not identified as memory in the device tree, and Linux will correctly give a virtual pointer but cache won't be enabled. Linux likely figures that "hey, this isn't memory, it's probably a low-level device" so it disables cache for this region. Bandwidth to/from DDR is not so great then.