Commit 1ae01d75 authored by Martin Jeřábek's avatar Martin Jeřábek Committed by Ille, Ondrej, Ing.
Browse files

userspace driver: add regtest utility

parent a43e3606
*.o
*.d
/test
/regtest
*.das
.*.cmd
.tmp_versions
......
SRCS := ctu_can_fd_hw.c ctu_can_fd_linux_defs.c ctu_can_fd_userspace.cpp
SRCS := ctu_can_fd_hw.c ctu_can_fd_linux_defs.c userspace_utils.cpp
OBJS := $(addsuffix .o,$(SRCS))
DEPS := $(addsuffix .d,$(SRCS))
DEPS := $(wildcard *.d)
P := arm-linux-gnueabihf-
......@@ -12,13 +12,15 @@ CFLAGS := $(XFLAGS) -Werror=implicit-function-declaration
CXXFLAGS := $(XFLAGS)
#LDFLAGS := -fuse-ld=gold
all: test
all: test regtest
ifeq ($(shell hostname),hathi)
cp ./test /srv/nfs4/debian-armhf-devel/
cp ./test ./regtest /srv/nfs4/debian-armhf-devel/
endif
test: $(OBJS)
$(CXX) $(XFLAGS) -o $@ $(OBJS) $(LDFLAGS)
test: $(OBJS) ctu_can_fd_userspace.cpp.o
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
regtest: $(OBJS) regtest.cpp.o
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
%.c.o: %.c
$(CC) $(CFLAGS) -MMD -MP -c $< -o $@
%.cpp.o: %.cpp
......@@ -26,6 +28,6 @@ test: $(OBJS)
.PHONY: all clean
clean:
-rm test $(OBJS) $(DEPS)
-rm test *.o $(DEPS)
-include $(DEPS)
extern "C" {
#include "ctu_can_fd_linux_defs.h"
#include "ctu_can_fd_hw.h"
}
#include "userspace_utils.h"
#undef abs
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <inttypes.h>
#include <err.h>
//#include "clara.hpp"
#include <iostream>
#define CANFD_ADDR_BASE 0x43C30000
#define CANFD_ADDR_RANGE 0x10000
static const char *memdev = "/dev/mem";
static int mem_fd = -1;
static void mem_open()
{
mem_fd = open(memdev, O_RDWR|O_SYNC);
if (mem_fd < 0) {
err(1, "open memory device");
}
}
void *mem_map(unsigned long mem_start, unsigned long mem_length)
{
unsigned long pagesize, mem_window_size;
void *mm, *mem;
//pagesize = getpagesize();
pagesize = sysconf(_SC_PAGESIZE);
mem_window_size = ((mem_start & (pagesize-1)) + mem_length + pagesize-1) & ~(pagesize-1);
mm = mmap(NULL, mem_window_size, PROT_WRITE|PROT_READ,
MAP_SHARED, mem_fd, mem_start & ~(pagesize-1));
mem = (char*)mm + (mem_start & (pagesize-1));
if (mm == MAP_FAILED) {
err(1, "mmap");
return NULL;
}
fprintf(stderr, "mmap 0x%lx -> %p\n",mem_start,mem);
return mem;
}
unsigned ctu_can_fd_read8(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg) {
return priv->read_reg(priv, (enum ctu_can_fd_regs)(reg & ~3)) >> (8 * (reg & 3));
}
unsigned ctu_can_fd_read16(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg) {
return priv->read_reg(priv, (enum ctu_can_fd_regs)(reg & ~1)) >> (8 * (reg & 1));
}
/*
void ctu_can_fd_write8(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg, uint8_t val) {
iowrite8(val, (uint8_t*)priv->mem_base + reg);
}
void ctu_can_fd_write16(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg, uint16_t val) {
iowrite16(val, (uint8_t*)priv->mem_base + reg);
}*/
int main(int argc, char *argv[])
{
......@@ -94,28 +29,7 @@ int main(int argc, char *argv[])
return 0;
}
}
/*
using namespace clara;
auto cli = //Opt(addr_base, "addr_base")
// ["-A"]["--addr_base"]("CAN FD registers base address")
Opt(ifc, "ifc") ["-i"]("CAN FD interface number")
| Opt(do_transmit)
["-t"]("Do transmit")
| Help(do_showhelp)
;
std::cout << "IFC:" << ifc << std::endl;
auto result = cli.parse(Args(argc, argv));
if (!result) {
std::cerr << "Error in command line: " << result.errorMessage() << std::endl;
exit(1);
}
if (do_showhelp) {
std::cout << cli;
return 0;
}
*/
static const uint32_t addrs[] = {0x43C30000, 0x43C70000};
if (ifc >= 2) {
std::cerr << "Err: ifc number must be 0 or 1.\n";
......@@ -123,18 +37,9 @@ int main(int argc, char *argv[])
}
addr_base = addrs[ifc];
mem_open();
volatile void * const base = mem_map(addr_base, CANFD_ADDR_RANGE);
struct ctucanfd_priv _p, *priv = &_p;
struct ctucanfd_priv *priv = ctucanfd_init(addr_base);
int res;
priv->mem_base = base;
priv->read_reg = ctu_can_fd_read32;
priv->write_reg = ctu_can_fd_write32;
union ctu_can_fd_device_id_version reg;
reg.u32 = priv->read_reg(priv, CTU_CAN_FD_DEVICE_ID);
......
#include "userspace_utils.h"
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
#include <iostream>
/*
Adapted from APB unit test.
Should check that the core is tied to CPU correctly and register access works.
Usage: ./regtest -a 0xAAAAAAAA, where AAAAAAAA is the IP memory map begin
*/
uint32_t s_apb_prdata;
struct ctucanfd_priv *priv;
unsigned error = 0;
void CHECK(uint32_t expected, const char *msg)
{
if (s_apb_prdata != expected) {
printf("%s: expected 0x%08x, got 0x%08x", msg, expected, s_apb_prdata);
error++;
}
}
void apb_write(uint32_t reg, uint32_t value, uint8_t be)
{
enum {
U8, U16, U32
} access;
int offset;
switch (be)
{
case 0b0001: access = U8; offset = 0; break;
case 0b0010: access = U8; offset = 1; break;
case 0b0100: access = U8; offset = 2; break;
case 0b1000: access = U8; offset = 3; break;
case 0b0011: access = U16; offset = 0; break;
case 0b1100: access = U16; offset = 2; break;
case 0b1111: access = U32; offset = 0; break;
default:
assert(!"invalid byte enable");
}
uint8_t * addr = (uint8_t*)priv->mem_base + reg;
switch (access)
{
case U8: iowrite8(value, addr+offset); break;
case U16: iowrite16(value, addr+offset); break;
case U32: iowrite32(value, addr+offset); break;
}
}
void apb_read(uint32_t reg)
{
uint8_t * addr = (uint8_t*)priv->mem_base + reg;
s_apb_prdata = ioread32(addr);
}
void apb_test_pattern(uint32_t reg, uint32_t data)
{
apb_write(reg, data, 0b1111);
apb_read(reg);
if (s_apb_prdata != data) {
printf("pattern 0x%08x mismatch: got 0x%08x", data, s_apb_prdata);
error++;
}
}
int main(int argc, char *argv[])
{
uint32_t addr_base = 0;
int c;
char *e;
const char *progname = argv[0];
while ((c = getopt(argc, argv, "a:th")) != -1) {
switch (c) {
case 'a':
addr_base = strtoul(optarg, &e, 0);
if (*e != '\0')
err(1, "-i expects a number");
break;
case 'h':
printf("Usage: %s [-a ifc_addr]\n\n",
progname
);
return 0;
}
}
if (addr_base < 0x40000000 || addr_base > 0xBFFFFFFF) {
std::cerr << "Err: ifc address must lie in AXI_GP0 or AXI_GP1 port range (on Zynq).\n";
exit(1);
}
if (addr_base & 0xFFF) {
std::cerr << "Err: ifc address must be aligned to at least 4096 bytes.\n";
exit(1);
}
priv = ctucanfd_init(addr_base);
union ctu_can_fd_device_id_version reg;
reg.u32 = priv->read_reg(priv, CTU_CAN_FD_DEVICE_ID);
printf("DevID: 0x%08x, should be 0x%08x\n", reg.s.device_id, CTU_CAN_FD_ID);
apb_read(CTU_CAN_FD_DEVICE_ID);
CHECK(0x0201CAFD, "CAN ID reg mismatch (just after HW reset)");
apb_write(CTU_CAN_FD_BTR, 0xFFFFFFFF, 0b1111);
apb_read(CTU_CAN_FD_DEVICE_ID);
CHECK(0x0201CAFD, "CAN ID reg mismatch");
apb_read(CTU_CAN_FD_BTR);
CHECK(0xFFFFFFFF, "readback mismatch");
apb_write(CTU_CAN_FD_BTR, 0x00000000, 0b0011);
apb_read(CTU_CAN_FD_BTR);
CHECK(0xFFFF0000, "write low word: readback mismatch");
apb_write(CTU_CAN_FD_BTR, 0xFFFFFFFF, 0b1111);
apb_write(CTU_CAN_FD_BTR, 0x00000000, 0b1100);
apb_read(CTU_CAN_FD_BTR);
CHECK(0x0000FFFF, "write high word: readback mismatch");
apb_test_pattern(CTU_CAN_FD_BTR, 0xAAAAAAAA);
apb_test_pattern(CTU_CAN_FD_BTR, 0x55555555);
apb_test_pattern(CTU_CAN_FD_BTR, 0x92492492);
apb_test_pattern(CTU_CAN_FD_BTR, 0x49249249);
apb_test_pattern(CTU_CAN_FD_BTR, 0x24924924);
apb_write(CTU_CAN_FD_BTR, 0x87654321, 0b1111);
apb_read(CTU_CAN_FD_BTR);
CHECK(0x87654321, "readback mismatch");
apb_write(CTU_CAN_FD_BTR, 0x000055aa, 0b0011);
apb_read(CTU_CAN_FD_BTR);
CHECK(0x876555aa, "write low word: readback mismatch");
if (error)
printf("There were %u errors.\n", error);
else
printf("Success!\n");
return error ? 1 : 0;
}
#include "userspace_utils.h"
#include <iostream>
static const char * const memdev = "/dev/mem";
static int mem_fd = -1;
#define CANFD_ADDR_RANGE 4096
static void mem_open()
{
if (mem_fd >= 0)
return;
mem_fd = open(memdev, O_RDWR|O_SYNC);
if (mem_fd < 0) {
err(1, "open memory device");
}
}
static void *mem_map(unsigned long mem_start, unsigned long mem_length)
{
unsigned long pagesize, mem_window_size;
void *mm, *mem;
//pagesize = getpagesize();
pagesize = sysconf(_SC_PAGESIZE);
mem_window_size = ((mem_start & (pagesize-1)) + mem_length + pagesize-1) & ~(pagesize-1);
mm = mmap(NULL, mem_window_size, PROT_WRITE|PROT_READ,
MAP_SHARED, mem_fd, mem_start & ~(pagesize-1));
mem = (char*)mm + (mem_start & (pagesize-1));
if (mm == MAP_FAILED) {
err(1, "mmap");
return NULL;
}
fprintf(stderr, "mmap 0x%lx -> %p\n",mem_start,mem);
return mem;
}
unsigned ctu_can_fd_read8(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg) {
return priv->read_reg(priv, (enum ctu_can_fd_regs)(reg & ~3)) >> (8 * (reg & 3));
}
unsigned ctu_can_fd_read16(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg) {
return priv->read_reg(priv, (enum ctu_can_fd_regs)(reg & ~1)) >> (8 * (reg & 1));
}
/*
void ctu_can_fd_write8(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg, uint8_t val) {
iowrite8(val, (uint8_t*)priv->mem_base + reg);
}
void ctu_can_fd_write16(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg, uint16_t val) {
iowrite16(val, (uint8_t*)priv->mem_base + reg);
}*/
struct ctucanfd_priv* ctucanfd_init(uint32_t addr)
{
mem_open();
volatile void * const base = mem_map(addr, CANFD_ADDR_RANGE);
struct ctucanfd_priv *priv = new ctucanfd_priv;
memset(priv, 0, sizeof(*priv));
priv->mem_base = base;
priv->read_reg = ctu_can_fd_read32;
priv->write_reg = ctu_can_fd_write32;
// will leak memory, but who cares, this is just a prototype testing tool
return priv;
}
#pragma once
extern "C" {
#include "ctu_can_fd_linux_defs.h"
#include "ctu_can_fd_hw.h"
}
#undef abs
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <inttypes.h>
#include <err.h>
struct ctucanfd_priv* ctucanfd_init(uint32_t addr);
unsigned ctu_can_fd_read8(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg);
unsigned ctu_can_fd_read16(struct ctucanfd_priv *priv, enum ctu_can_fd_regs reg);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment