/*
* Copyright (C) 2013 - 2016 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or (b) that interact
* with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in this
* Software without prior written authorization from Xilinx.
*
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/vt.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <semaphore.h>
#include <sys/sysinfo.h>
#define __USE_GNU
//#define _GPU_SOURCE
#include <sched.h>
#include <pthread.h>
// Channel 0 register space
#define CTRL_REG_BASE_ADDR (0xA0010000)
#define CTRL_REG_SIZE (4096)
#define CTRL_MAP_MASK (CTRL_REG_SIZE - 1)
#define MAX_CHANNELS (4)
unsigned long dma_base_addr;
int DMA_MEMORY_SIZE;
int DMA_MAX_PKT_UNIT;
void *chan_base, *chan_ptr;
void dma_init(void);
void usage(void);
int main(int argc, char **argv)
{
int c;
int ret;
off_t target;
char *ch, *sd, *ud;
int channel, size, unit;
int fd_mem, fd_dma;
printf("dmaconf start.\n");
while((c = getopt(argc, argv, "c:s:u:h")) != -1) {
switch(c) {
case 'c':
ch = optarg;
break;
case 's':
sd = optarg;
break;
case 'u':
ud = optarg;
break;
case 'h':
usage();
return 0;
default:
printf("invalid option: %c\n", (char)c);
usage();
exit(0);
}
}
channel = strtoul(ch, NULL, 10);
size = strtoul(sd, NULL, 10);
unit = strtoul(ud, NULL, 10);
DMA_MEMORY_SIZE = size * 1024 * 1024;
DMA_MAX_PKT_UNIT = unit * 1024 * 1024;
switch(channel)
{
case 0:
fd_dma = open("/dev/memdev0", O_RDWR | O_ASYNC);
break;
case 1:
fd_dma = open("/dev/memdev1", O_RDWR | O_ASYNC);
break;
case 2:
fd_dma = open("/dev/memdev2", O_RDWR | O_ASYNC);
break;
case 3:
fd_dma = open("/dev/memdev3", O_RDWR | O_ASYNC);
break;
default:
printf("Invalid Channel Number: 0~%d.\n", MAX_CHANNELS - 1);
exit(0);
}
/* open /dev/memdev, this is the first time */
if(fd_dma==-1)
{
printf("/dev/memdevx opened error.\n");
}
fflush(stdout);
/* open /dev/mem */
if((fd_mem=open("/dev/mem", O_RDWR | O_ASYNC))==-1)
{
printf("/dev/mem opened error.\n");
}
fflush(stdout);
/* map CHANNEL0_base_addr to user space */
target = CTRL_REG_BASE_ADDR + channel*CTRL_REG_SIZE;
chan_base = mmap(0, CTRL_REG_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd_mem, target & ~CTRL_MAP_MASK);
if(chan_base == (void *) -1)
{
printf("ctrl0 mapped failed.\n");
}
fflush(stdout);
chan_ptr = chan_base + (target & CTRL_MAP_MASK);
// set DMA_MEMORY_SIZE and get dma_base_addr
dma_base_addr = DMA_MEMORY_SIZE;
ioctl(fd_dma, 0, &dma_base_addr);
printf("dma_base_addr %lx\n", dma_base_addr);
dma_init();
munmap(chan_base, CTRL_REG_SIZE);
close(fd_mem);
close(fd_dma);
return 0;
}
void usage(void)
{
printf("-m /dev/memdev -c channel -s dma_momory_size -u unit -h usage\n");
return;
}
void dma_init()
{
/* s2mm dma configuration */
*((volatile unsigned int *)(chan_ptr + 0x00)) = dma_base_addr;
*((volatile unsigned int *)(chan_ptr + 0x04)) = dma_base_addr >> 32;
*((volatile unsigned int *)(chan_ptr + 0x08)) = DMA_MAX_PKT_UNIT;
*((volatile unsigned int *)(chan_ptr + 0x0C)) = DMA_MEMORY_SIZE / DMA_MAX_PKT_UNIT;
}