[Cryptech-Commits] [test/novena_base] 04/05: Reformat C code for readability, remove non-API stuff from novena-eim.h, change eim_setup() success value to 0.

git at cryptech.is git at cryptech.is
Wed Feb 11 17:51:20 UTC 2015


This is an automated email from the git hooks/post-receive script.

paul at psgd.org pushed a commit to branch coretest_hashes
in repository test/novena_base.

commit ba254d4d83bed050f16026b750d6a7d175098c77
Author: Paul Selkirk <paul at psgd.org>
Date:   Wed Feb 11 12:13:23 2015 -0500

    Reformat C code for readability, remove non-API stuff from novena-eim.h, change eim_setup() success value to 0.
---
 sw/hash_tester.c |  286 +++++++-------
 sw/novena-eim.c  | 1106 ++++++++++++++++++++++++++++++++++--------------------
 sw/novena-eim.h  |  349 +++--------------
 3 files changed, 894 insertions(+), 847 deletions(-)

diff --git a/sw/hash_tester.c b/sw/hash_tester.c
index 4fbeaa3..a0ab0f1 100644
--- a/sw/hash_tester.c
+++ b/sw/hash_tester.c
@@ -63,13 +63,13 @@ int quiet = 0;
 int repeat = 0;
 
 /* instead of core number 0 we have a page of global registers */
-#define ADDR_GLOBAL_BOARD_TYPE		EIM_BASE_ADDR + (0x00 << 2)
-#define ADDR_GLOBAL_BITSTREAM_VER	EIM_BASE_ADDR + (0x01 << 2)
-#define ADDR_GLOBAL_DUMMY_REG		EIM_BASE_ADDR + (0xFF << 2)
+#define ADDR_GLOBAL_BOARD_TYPE          EIM_BASE_ADDR + (0x00 << 2)
+#define ADDR_GLOBAL_BITSTREAM_VER       EIM_BASE_ADDR + (0x01 << 2)
+#define ADDR_GLOBAL_DUMMY_REG           EIM_BASE_ADDR + (0xFF << 2)
 
-#define SEGMENT_OFFSET_HASHES	EIM_BASE_ADDR + 0x000000
-#define SEGMENT_OFFSET_RNGS		EIM_BASE_ADDR + 0x010000
-#define SEGMENT_OFFSET_CIPHERS	EIM_BASE_ADDR + 0x020000
+#define SEGMENT_OFFSET_HASHES   EIM_BASE_ADDR + 0x000000
+#define SEGMENT_OFFSET_RNGS     EIM_BASE_ADDR + 0x010000
+#define SEGMENT_OFFSET_CIPHERS  EIM_BASE_ADDR + 0x020000
 
 
 /* addresses and codes common to all hash cores */
@@ -85,10 +85,10 @@ int repeat = 0;
 #define ADDR_BLOCK              0x40
 #define ADDR_DIGEST             0x80
 
-#define HASH_CORE_SIZE			0x400
+#define HASH_CORE_SIZE          0x400
 
 /* addresses and codes for the specific hash cores */
-#define SHA1_ADDR_BASE          EIM_BASE_ADDR  + (1*HASH_CORE_SIZE)
+#define SHA1_ADDR_BASE          SEGMENT_OFFSET_HASHES + (1*HASH_CORE_SIZE)
 #define SHA1_ADDR_NAME0         SHA1_ADDR_BASE + ADDR_NAME0
 #define SHA1_ADDR_NAME1         SHA1_ADDR_BASE + ADDR_NAME1
 #define SHA1_ADDR_VERSION       SHA1_ADDR_BASE + ADDR_VERSION
@@ -99,7 +99,7 @@ int repeat = 0;
 #define SHA1_BLOCK_LEN          512 / 8
 #define SHA1_DIGEST_LEN         160 / 8
 
-#define SHA256_ADDR_BASE		EIM_BASE_ADDR    + (2*HASH_CORE_SIZE)
+#define SHA256_ADDR_BASE        SEGMENT_OFFSET_HASHES + (2*HASH_CORE_SIZE)
 #define SHA256_ADDR_NAME0       SHA256_ADDR_BASE + ADDR_NAME0
 #define SHA256_ADDR_NAME1       SHA256_ADDR_BASE + ADDR_NAME1
 #define SHA256_ADDR_VERSION     SHA256_ADDR_BASE + ADDR_VERSION
@@ -110,7 +110,7 @@ int repeat = 0;
 #define SHA256_BLOCK_LEN        512 / 8
 #define SHA256_DIGEST_LEN       256 / 8
 
-#define SHA512_ADDR_BASE        EIM_BASE_ADDR    + (3*HASH_CORE_SIZE)
+#define SHA512_ADDR_BASE        SEGMENT_OFFSET_HASHES + (3*HASH_CORE_SIZE)
 #define SHA512_ADDR_NAME0       SHA512_ADDR_BASE + ADDR_NAME0
 #define SHA512_ADDR_NAME1       SHA512_ADDR_BASE + ADDR_NAME1
 #define SHA512_ADDR_VERSION     SHA512_ADDR_BASE + ADDR_VERSION
@@ -300,11 +300,11 @@ const uint8_t SHA512_DOUBLE_DIGEST[] =
 void dump(char *label, const uint8_t *buf, int len)
 {
     if (debug) {
-	int i;
-	printf("%s [", label);
-	for (i = 0; i < len; ++i)
-	    printf(" %02x", buf[i]);
-	printf(" ]\n");
+        int i;
+        printf("%s [", label);
+        for (i = 0; i < len; ++i)
+            printf(" %02x", buf[i]);
+        printf(" ]\n");
     }
 }
 
@@ -313,9 +313,9 @@ int tc_write(off_t offset, const uint8_t *buf, int len)
     dump("write ", buf, len);
 
     for (; len > 0; offset += 4, buf += 4, len -= 4) {
-	uint32_t val;
-	val = htonl(*(uint32_t *)buf);
-	eim_write_32(offset, &val);
+        uint32_t val;
+        val = htonl(*(uint32_t *)buf);
+        eim_write_32(offset, &val);
     }
 
     return 0;
@@ -327,9 +327,9 @@ int tc_read(off_t offset, uint8_t *buf, int len)
     int rlen = len;
 
     for (; rlen > 0; offset += 4, rbuf += 4, rlen -= 4) {
-	uint32_t val;
-	eim_read_32(offset, &val);
-	*(uint32_t *)rbuf = ntohl(val);
+        uint32_t val;
+        eim_read_32(offset, &val);
+        *(uint32_t *)rbuf = ntohl(val);
     }
 
     dump("read  ", buf, len);
@@ -396,14 +396,14 @@ int tc_wait(off_t offset, uint8_t status)
     for (i = 0; i < 10; ++i) {
         if (tc_read(offset, buf, 4) != 0)
             return 1;
-	if (buf[3] & status)
-	    return 0;
+        if (buf[3] & status)
+            return 0;
     }
     fprintf(stderr, "tc_wait timed out\n");
     return 1;
 #endif
 }
-        
+
 int tc_wait_ready(off_t offset)
 {
     return tc_wait(offset, STATUS_READY_BIT);
@@ -414,6 +414,45 @@ int tc_wait_valid(off_t offset)
     return tc_wait(offset, STATUS_VALID_BIT);
 }
 
+/* ---------------- sanity test case ---------------- */
+
+int TC0()
+{
+    uint8_t board_type[4]       = { 'P', 'V', 'T', '1'};        /* "PVT1" */
+    uint8_t bitstream_ver[4]    = { 0x00, 0x01, 0x00, 0x0B };   /* v0.1.0b */
+    uint8_t t[4];
+
+    uint8_t seg_rngs_reg_first[4]       = { 0xAA, 0xAA, 0xAA, 0xAA};
+    uint8_t seg_rngs_reg_second[4]      = { 0xBB, 0xBB, 0xBB, 0xBB};
+    uint8_t seg_rngs_reg_third[4]       = { 0xCC, 0xCC, 0xCC, 0xCC};
+
+    uint8_t seg_ciphers_reg_first[4]    = { 0xDD, 0xDD, 0xDD, 0xDD};
+    uint8_t seg_ciphers_reg_second[4]   = { 0xEE, 0xEE, 0xEE, 0xEE};
+    uint8_t seg_ciphers_reg_third[4]    = { 0xFF, 0xFF, 0xFF, 0xFF};
+
+    if (!quiet)
+        printf("TC0: Reading board type, version, and dummy reg from global registers.\n");
+
+    /* write current time into dummy register, then try to read it back
+     * to make sure that we can actually write something into EIM
+     */
+    (void)time((time_t *)t);
+    tc_write(ADDR_GLOBAL_DUMMY_REG, (void *)&t, 4);
+
+    return
+        tc_expected(ADDR_GLOBAL_BOARD_TYPE,    board_type,    4) ||
+        tc_expected(ADDR_GLOBAL_BITSTREAM_VER, bitstream_ver, 4) || 
+        tc_expected(ADDR_GLOBAL_DUMMY_REG,     (void *)t,     4) ||
+
+        tc_expected(SEGMENT_OFFSET_RNGS + (0 << 2), seg_rngs_reg_first,  4) ||
+        tc_expected(SEGMENT_OFFSET_RNGS + (1 << 2), seg_rngs_reg_second, 4) ||
+        tc_expected(SEGMENT_OFFSET_RNGS + (2 << 2), seg_rngs_reg_third,  4) ||
+
+        tc_expected(SEGMENT_OFFSET_CIPHERS + (0 << 2), seg_ciphers_reg_first,  4) ||
+        tc_expected(SEGMENT_OFFSET_CIPHERS + (1 << 2), seg_ciphers_reg_second, 4) ||
+        tc_expected(SEGMENT_OFFSET_CIPHERS + (2 << 2), seg_ciphers_reg_third,  4);
+}
+
 /* ---------------- SHA-1 test cases ---------------- */
 
 /* TC1: Read name and version from SHA-1 core. */
@@ -424,7 +463,7 @@ int TC1(void)
     uint8_t version[4] = { 0x30, 0x2e, 0x35, 0x30 };    /* "0.50" */
 
     if (!quiet)
-	printf("TC1: Reading name, type and version words from SHA-1 core.\n");
+        printf("TC1: Reading name, type and version words from SHA-1 core.\n");
 
     return
         tc_expected(SHA1_ADDR_NAME0, name0, 4) ||
@@ -440,7 +479,7 @@ int TC2(void)
     int ret;
 
     if (!quiet)
-	printf("TC2: Single block message test for SHA-1.\n");
+        printf("TC2: Single block message test for SHA-1.\n");
 
     /* Write block to SHA-1. */
     tc_write(SHA1_ADDR_BLOCK, block, SHA1_BLOCK_LEN);
@@ -464,7 +503,7 @@ int TC3(void)
     int ret;
 
     if (!quiet)
-	printf("TC3: Double block message test for SHA-1.\n");
+        printf("TC3: Double block message test for SHA-1.\n");
 
     /* Write first block to SHA-1. */
     tc_write(SHA1_ADDR_BLOCK, block[0], SHA1_BLOCK_LEN);
@@ -493,7 +532,7 @@ int TC4(void)
     uint8_t version[4] = { 0x30, 0x2e, 0x38, 0x30 };    /* "0.80" */
 
     if (!quiet)
-	printf("TC4: Reading name, type and version words from SHA-256 core.\n");
+        printf("TC4: Reading name, type and version words from SHA-256 core.\n");
 
     return
         tc_expected(SHA256_ADDR_NAME0, name0, 4) ||
@@ -508,7 +547,7 @@ int TC5()
     const uint8_t *expected = SHA256_SINGLE_DIGEST;
 
     if (!quiet)
-	printf("TC5: Single block message test for SHA-256.\n");
+        printf("TC5: Single block message test for SHA-256.\n");
 
     return
         /* Write block to SHA-256. */
@@ -532,7 +571,7 @@ int TC6()
     const uint8_t *expected = SHA256_DOUBLE_DIGEST;
 
     if (!quiet)
-	printf("TC6: Double block message test for SHA-256.\n");
+        printf("TC6: Double block message test for SHA-256.\n");
 
     return
         /* Write first block to SHA-256. */
@@ -574,11 +613,11 @@ int TC7()
     int i, n = 1000;
 
     if (!quiet)
-	printf("TC7: Message with %d blocks test for SHA-256.\n", n);
+        printf("TC7: Message with %d blocks test for SHA-256.\n", n);
 
     /* Write block data to SHA-256. */
     if (tc_write(SHA256_ADDR_BLOCK, block, SHA256_BLOCK_LEN))
-	return 1;
+        return 1;
 
     /* Start initial block hashing, wait and check status. */
     if (tc_init(SHA256_ADDR_CTRL) ||
@@ -605,12 +644,12 @@ int TC7()
 /* TC8: Read name and version from SHA-512 core. */
 int TC8()
 {
-    uint8_t name0[4]   = { 0x73, 0x68, 0x61, 0x32 };	/* "sha2" */
-    uint8_t name1[4]   = { 0x2d, 0x35, 0x31, 0x32 };	/* "-512" */
-    uint8_t version[4] = { 0x30, 0x2e, 0x38, 0x30 };	/* "0.80" */
+    uint8_t name0[4]   = { 0x73, 0x68, 0x61, 0x32 };    /* "sha2" */
+    uint8_t name1[4]   = { 0x2d, 0x35, 0x31, 0x32 };    /* "-512" */
+    uint8_t version[4] = { 0x30, 0x2e, 0x38, 0x30 };    /* "0.80" */
 
     if (!quiet)
-	printf("TC8: Reading name, type and version words from SHA-512 core.\n");
+        printf("TC8: Reading name, type and version words from SHA-512 core.\n");
 
     return
         tc_expected(SHA512_ADDR_NAME0, name0, 4) ||
@@ -638,22 +677,22 @@ int tc9(int mode, const uint8_t *expected, int digest_len)
 int TC9()
 {
     if (!quiet)
-	printf("TC9-1: Single block message test for SHA-512/224.\n");
+        printf("TC9-1: Single block message test for SHA-512/224.\n");
     if (tc9(MODE_SHA_512_224, SHA512_224_SINGLE_DIGEST, SHA512_224_DIGEST_LEN) != 0)
         return 1;
 
     if (!quiet)
-	printf("TC9-2: Single block message test for SHA-512/256.\n");
+        printf("TC9-2: Single block message test for SHA-512/256.\n");
     if (tc9(MODE_SHA_512_256, SHA512_256_SINGLE_DIGEST, SHA512_256_DIGEST_LEN) != 0)
         return 1;
 
     if (!quiet)
-	printf("TC9-3: Single block message test for SHA-384.\n");
+        printf("TC9-3: Single block message test for SHA-384.\n");
     if (tc9(MODE_SHA_384, SHA384_SINGLE_DIGEST, SHA384_DIGEST_LEN) != 0)
         return 1;
 
     if (!quiet)
-	printf("TC9-4: Single block message test for SHA-512.\n");
+        printf("TC9-4: Single block message test for SHA-512.\n");
     if (tc9(MODE_SHA_512, SHA512_SINGLE_DIGEST, SHA512_DIGEST_LEN) != 0)
         return 1;
 
@@ -686,68 +725,31 @@ int tc10(int mode, const uint8_t *expected, int digest_len)
 int TC10()
 {
     if (!quiet)
-	printf("TC10-1: Double block message test for SHA-512/224.\n");
+        printf("TC10-1: Double block message test for SHA-512/224.\n");
     if (tc10(MODE_SHA_512_224, SHA512_224_DOUBLE_DIGEST, SHA512_224_DIGEST_LEN) != 0)
         return 1;
 
     if (!quiet)
-	printf("TC10-2: Double block message test for SHA-512/256.\n");
+        printf("TC10-2: Double block message test for SHA-512/256.\n");
     if (tc10(MODE_SHA_512_256, SHA512_256_DOUBLE_DIGEST, SHA512_256_DIGEST_LEN) != 0)
         return 1;
 
     if (!quiet)
-	printf("TC10-3: Double block message test for SHA-384.\n");
+        printf("TC10-3: Double block message test for SHA-384.\n");
     if (tc10(MODE_SHA_384, SHA384_DOUBLE_DIGEST, SHA384_DIGEST_LEN) != 0)
         return 1;
 
     if (!quiet)
-	printf("TC10-4: Double block message test for SHA-512.\n");
+        printf("TC10-4: Double block message test for SHA-512.\n");
     if (tc10(MODE_SHA_512, SHA512_DOUBLE_DIGEST, SHA512_DIGEST_LEN) != 0)
         return 1;
 
     return 0;
 }
 
-int TC11()
-{
-	uint8_t board_type[4]   	= { 'P', 'V', 'T', '1'};		/* "PVT1" */
-    uint8_t bitstream_ver[4]	= { 0x00, 0x01, 0x00, 0x0B };	/* v0.1.0b */
-	uint8_t t[4];
-	
-	uint8_t seg_rngs_reg_first[4]   = { 0xAA, 0xAA, 0xAA, 0xAA};
-	uint8_t seg_rngs_reg_second[4]	= { 0xBB, 0xBB, 0xBB, 0xBB};
-	uint8_t seg_rngs_reg_third[4]   = { 0xCC, 0xCC, 0xCC, 0xCC};
-
-	uint8_t seg_ciphers_reg_first[4]	= { 0xDD, 0xDD, 0xDD, 0xDD};
-	uint8_t seg_ciphers_reg_second[4]	= { 0xEE, 0xEE, 0xEE, 0xEE};
-	uint8_t seg_ciphers_reg_third[4]	= { 0xFF, 0xFF, 0xFF, 0xFF};
-	
-		// write current time into dummy register, then try to read it back
-		// to make sure that we can actually write something into eim
-	(void)time((time_t *)t);
-	tc_write(ADDR_GLOBAL_DUMMY_REG, (void *)&t, 4);
-	
-    if (!quiet)
-		printf("TC11: Reading board type, bitstream version and dummy register from global registers.\n");
-    if (!quiet)
-		printf("TC11: Reading dummy registers from RNG and CIPHER memory segments.\n");		
-		
-    return
-        tc_expected(ADDR_GLOBAL_BOARD_TYPE,    board_type,    4) ||
-        tc_expected(ADDR_GLOBAL_BITSTREAM_VER, bitstream_ver, 4) || 
-		tc_expected(ADDR_GLOBAL_DUMMY_REG,     (void *)t,     4) ||
-		
-		tc_expected(SEGMENT_OFFSET_RNGS + (0 << 2), seg_rngs_reg_first,  4) ||
-		tc_expected(SEGMENT_OFFSET_RNGS + (1 << 2), seg_rngs_reg_second, 4) ||
-		tc_expected(SEGMENT_OFFSET_RNGS + (2 << 2), seg_rngs_reg_third,  4) ||
-		
-		tc_expected(SEGMENT_OFFSET_CIPHERS + (0 << 2), seg_ciphers_reg_first,  4) ||
-		tc_expected(SEGMENT_OFFSET_CIPHERS + (1 << 2), seg_ciphers_reg_second, 4) ||
-		tc_expected(SEGMENT_OFFSET_CIPHERS + (2 << 2), seg_ciphers_reg_third,  4);
-}
-
 /* ---------------- main ---------------- */
 
+/* signal handler for ctrl-c to end repeat testing */
 unsigned long iter = 0;
 struct timeval tv_start, tv_end;
 void sighandler(int unused)
@@ -756,19 +758,19 @@ void sighandler(int unused)
 
     gettimeofday(&tv_end, NULL);
     tv_diff = (double)(tv_end.tv_sec - tv_start.tv_sec) +
-	(double)(tv_end.tv_usec - tv_start.tv_usec)/1000000;
+        (double)(tv_end.tv_usec - tv_start.tv_usec)/1000000;
     printf("\n%lu iterations in %.3f seconds (%.3f iterations/sec)\n",
-	   iter, tv_diff, (double)iter/tv_diff);
-    exit(0);
+           iter, tv_diff, (double)iter/tv_diff);
+    exit(EXIT_SUCCESS);
 }
 
 int main(int argc, char *argv[])
 {
     typedef int (*tcfp)(void);
+    tcfp all_tests[] = { TC0, TC1, TC2, TC3, TC4, TC5, TC6, TC7, TC8, TC9, TC10 };
     tcfp sha1_tests[] = { TC1, TC2, TC3 };
     tcfp sha256_tests[] = { TC4, TC5, TC6, TC7 };
     tcfp sha512_tests[] = { TC8, TC9, TC10 };
-    tcfp all_tests[] = { TC1, TC2, TC3, TC4, TC5, TC6, TC7, TC8, TC9, TC10, TC11 };
 
     char *usage = "Usage: %s [-h] [-d] [-q] [-r] tc...\n";
     int i, j, opt;
@@ -778,99 +780,97 @@ int main(int argc, char *argv[])
         case 'h':
         case '?':
             printf(usage, argv[0]);
-            return 0;
+            return EXIT_SUCCESS;
         case 'd':
             debug = 1;
             break;
-	case 'q':
-	    quiet = 1;
-	    break;
-	case 'r':
-	    repeat = 1;
-	    break;
+        case 'q':
+            quiet = 1;
+            break;
+        case 'r':
+            repeat = 1;
+            break;
         default:
             fprintf(stderr, usage, argv[0]);
-            return 1;
+            return EXIT_FAILURE;
         }
     }
 
-    // try to setup eim (return value should be 1)
-    printf("Configuring EIM .. ");
-    if (eim_setup() < 1) {
-	printf("ERROR\n");
-	return EXIT_FAILURE;
-    }
-    else {
-	printf("EIM Setup ok.\n");
+    /* set up EIM */
+    if (eim_setup() != 0) {
+        fprintf(stderr, "EIM setup failed\n");
+        return EXIT_FAILURE;
     }
 
+    /* repeat one test until interrupted */
     if (repeat) {
-	tcfp tc;
-	if (optind != argc - 1) {
-	    fprintf(stderr, "only one test case can be repeated\n");
-	    return 1;
-	}
-	j = atoi(argv[optind]);
-	if (j <= 0 || j > sizeof(all_tests)/sizeof(all_tests[0])) {
-	    fprintf(stderr, "invalid test number %s\n", argv[optind]);
-	    return 1;
-	}
-	tc = (all_tests[j - 1]);
-	srand(time(NULL));
-	signal(SIGINT, sighandler);
-	gettimeofday(&tv_start, NULL);
-	while (1) {
-	    ++iter;
-	    if ((iter & 0xffff) == 0) {
-		printf(".");
-		fflush(stdout);
-	    }
-	    if (tc() != 0)
-		sighandler(0);
-	}
-	return 0;	/*NOTREACHED*/
+        tcfp tc;
+        if (optind != argc - 1) {
+            fprintf(stderr, "only one test case can be repeated\n");
+            return EXIT_FAILURE;
+        }
+        j = atoi(argv[optind]);
+        if (j < 0 || j >= sizeof(all_tests)/sizeof(all_tests[0])) {
+            fprintf(stderr, "invalid test number %s\n", argv[optind]);
+            return EXIT_FAILURE;
+        }
+        tc = (all_tests[j]);
+        srand(time(NULL));
+        signal(SIGINT, sighandler);
+        gettimeofday(&tv_start, NULL);
+        while (1) {
+            ++iter;
+            if ((iter & 0xffff) == 0) {
+                printf(".");
+                fflush(stdout);
+            }
+            if (tc() != 0)
+                sighandler(0);
+        }
+        return EXIT_SUCCESS;    /*NOTREACHED*/
     }
 
     /* no args == run all tests */
     if (optind >= argc) {
         for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
             if (all_tests[j]() != 0)
-                return 1;
-        return 0;
+                return EXIT_FAILURE;
+        return EXIT_SUCCESS;
     }
 
+    /* run one or more tests (by number) or groups of tests (by name) */
     for (i = optind; i < argc; ++i) {
-        if (strcmp(argv[i], "sha1") == 0) {
+        if (strcmp(argv[i], "all") == 0) {
+            for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
+                if (all_tests[j]() != 0)
+                    return EXIT_FAILURE;
+        }
+        else if (strcmp(argv[i], "sha1") == 0) {
             for (j = 0; j < sizeof(sha1_tests)/sizeof(sha1_tests[0]); ++j)
                 if (sha1_tests[j]() != 0)
-                    return 1;
+                    return EXIT_FAILURE;
         }
         else if (strcmp(argv[i], "sha256") == 0) {
             for (j = 0; j < sizeof(sha256_tests)/sizeof(sha256_tests[0]); ++j)
                 if (sha256_tests[j]() != 0)
-                    return 1;
+                    return EXIT_FAILURE;
         }
         else if (strcmp(argv[i], "sha512") == 0) {
             for (j = 0; j < sizeof(sha512_tests)/sizeof(sha512_tests[0]); ++j)
                 if (sha512_tests[j]() != 0)
-                    return 1;
-        }
-        else if (strcmp(argv[i], "all") == 0) {
-            for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
-                if (all_tests[j]() != 0)
-                    return 1;
+                    return EXIT_FAILURE;
         }
         else if (isdigit(argv[i][0]) &&
-                 (((j = atoi(argv[i])) > 0) &&
-                  (j <= sizeof(all_tests)/sizeof(all_tests[0])))) {
-            if (all_tests[j - 1]() != 0)
-                return 1;
+                 (((j = atoi(argv[i])) >= 0) &&
+                  (j < sizeof(all_tests)/sizeof(all_tests[0])))) {
+            if (all_tests[j]() != 0)
+                return EXIT_FAILURE;
         }
         else {
             fprintf(stderr, "unknown test case %s\n", argv[i]);
-            return 1;
+            return EXIT_FAILURE;
         }
     }
 
-    return 0;
+    return EXIT_SUCCESS;
 }
diff --git a/sw/novena-eim.c b/sw/novena-eim.c
index 1effff1..9b3d236 100644
--- a/sw/novena-eim.c
+++ b/sw/novena-eim.c
@@ -1,407 +1,699 @@
-//------------------------------------------------------------------------------
-// novena-eim.c
-//------------------------------------------------------------------------------
-
-
-//------------------------------------------------------------------------------
-// Headers
-//------------------------------------------------------------------------------
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <sys/mman.h>
-#include "novena-eim.h"
-
-
-//------------------------------------------------------------------------------
-// Variables
-//------------------------------------------------------------------------------
-static long		mem_page_size	= 0;
-static int		mem_dev_fd		= -1;
-static void *	mem_map_ptr		= MAP_FAILED;
-static off_t	mem_base_addr	= 0;
-
-
-//------------------------------------------------------------------------------
-int eim_setup()
-//------------------------------------------------------------------------------
-{
-		// register cleanup function
-	int ok = atexit(_eim_cleanup);
-	if (ok != 0)
-	{	printf("ERROR: atexit() failed.\n");
-		return -1;
-	}
-	
-		// determine memory page size to use in mmap()
-	mem_page_size = sysconf(_SC_PAGESIZE);
-	if (mem_page_size < 1)
-	{	printf("ERROR: sysconf(_SC_PAGESIZE) == %ld\n", mem_page_size);
-		return -1;
-	}
-	
-		// try to open memory device
-	mem_dev_fd = open(MEMORY_DEVICE, O_RDWR | O_SYNC);
-	if (mem_dev_fd == -1)
-	{	printf("ERROR: open(%s) failed.\n", MEMORY_DEVICE);
-		return -1;
-	}
-
-		/* Several blocks in the CPU have common pins, we can use I/O MUX Controller
-		 * to configure what block will actually use I/O pins. We wait EIM module to be able
-		 * to communicate with the on-board FPGA. Let's configure IOMUXC accordingly.
-		 */
-	_eim_setup_iomuxc();
-	
-		/* We need to enable clocking of EIM block in order to be able to use it.
-		 * Let's configure Clock Controller Module accordingly.
-		 */
-	_eim_setup_ccm();
-	
-		/* We need to properly configure EIM mode and all the corresponding parameters.
-		 * That's a lot of code, let's do it now.
-		 */
-	_eim_setup_eim();
-	
-	
-		// done
-	return 1;
-}
-
-
-//------------------------------------------------------------------------------
-void _eim_cleanup()
-//------------------------------------------------------------------------------
-{
-		// unmap memory if needed
-	if (mem_map_ptr != MAP_FAILED)
-	{	int ok = munmap(mem_map_ptr, mem_page_size);
-		if (ok != 0) printf("WARNING: munmap() failed.\n");
-	}
-
-		// close memory device if needed
-	if (mem_dev_fd != -1)
-	{	int ok = close(mem_dev_fd);
-		if (ok != 0) printf("WARNING: close() failed.\n");
-	}
-}
-
-
-//------------------------------------------------------------------------------
-void _eim_setup_iomuxc()
-//------------------------------------------------------------------------------
-{
-		// create structures
-	struct IOMUXC_SW_MUX_CTL_PAD_EIM	reg_mux;				// mux control register
-	struct IOMUXC_SW_PAD_CTL_PAD_EIM	reg_pad;				// pad control register
-	
-		// setup mux control register
-	reg_mux.mux_mode		= IOMUXC_MUX_MODE_ALT0;				// ALT0 mode must be used for EIM
-	reg_mux.sion			= 0;								// forced input not needed
-	reg_mux.reserved_3		= 0;								// must be 0
-	reg_mux.reserved_31_5	= 0;								// must be 0
-
-		// setup pad control register
-	reg_pad.sre				= IOMUXC_PAD_CTL_SRE_FAST;			// fast slew rate
-	reg_pad.dse				= IOMUXC_PAD_CTL_DSE_33_OHM;		// highest drive strength
-	reg_pad.speed			= IOMUXC_PAD_CTL_SPEED_MEDIUM_10;	// medium speed
-	reg_pad.ode				= IOMUXC_PAD_CTL_ODE_DISABLED;		// open drain not needed
-	reg_pad.pke				= IOMUXC_PAD_CTL_PKE_DISABLED;		// neither pull nor keeper are needed
-	reg_pad.pue				= IOMUXC_PAD_CTL_PUE_PULL;			// doesn't matter actually, because PKE is disabled
-	reg_pad.pus				= IOMUXC_PAD_CTL_PUS_100K_OHM_PU;	// doesn't matter actually, because PKE is disabled
-	reg_pad.hys				= IOMUXC_PAD_CTL_HYS_DISABLED;		// use CMOS, not Schmitt trigger input
-	reg_pad.reserved_2_1	= 0;								// must be 0
-	reg_pad.reserved_10_8	= 0;								// must be 0
-	reg_pad.reserved_31_17	= 0;								// must be 0
-
-		// all the pins must be configured to use the same ALT0 mode
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_CS0_B,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_OE_B,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_RW,		(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_LBA_B,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD00,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD01,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD02,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD03,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD04,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD05,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD06,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD07,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD08,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD09,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD10,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD11,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD12,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD13,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD14,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD15,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_WAIT_B,	(uint32_t *)&reg_mux);
-	eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_BCLK,	(uint32_t *)&reg_mux);
-
-		// we need to configure all the I/O pads too
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_CS0_B,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_OE_B,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_RW,		(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_LBA_B,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD00,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD01,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD02,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD03,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD04,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD05,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD06,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD07,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD08,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD09,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD10,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD11,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD12,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD13,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD14,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD15,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_WAIT_B,	(uint32_t *)&reg_pad);
-	eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_BCLK,	(uint32_t *)&reg_pad);
-}
-
-
-//------------------------------------------------------------------------------
-void _eim_setup_ccm()
-//------------------------------------------------------------------------------
-{
-		// create structure
-	struct CCM_CCGR6 ccm_ccgr6;
-	
-		// read register
-	eim_read_32(CCM_CCGR6, (uint32_t *)&ccm_ccgr6);
-	
-		// modify register
-	ccm_ccgr6.cg0_usboh3		= CCM_CGR_ON_EXCEPT_STOP;
-	ccm_ccgr6.cg1_usdhc1		= CCM_CGR_OFF;
-	ccm_ccgr6.cg2_usdhc2		= CCM_CGR_ON_EXCEPT_STOP;
-	ccm_ccgr6.cg3_usdhc3		= CCM_CGR_ON_EXCEPT_STOP;
-	
-	ccm_ccgr6.cg3_usdhc4		= CCM_CGR_OFF;
-	ccm_ccgr6.cg5_eim_slow		= CCM_CGR_ON_EXCEPT_STOP;
-	ccm_ccgr6.cg6_vdoaxiclk		= CCM_CGR_OFF;
-	ccm_ccgr6.cg7_vpu			= CCM_CGR_OFF;
-	
-	ccm_ccgr6.cg8_reserved		= 0;
-	ccm_ccgr6.cg9_reserved		= 0;
-	ccm_ccgr6.cg10_reserved		= 0;
-	ccm_ccgr6.cg11_reserved		= 0;
-	ccm_ccgr6.cg12_reserved		= 0;
-	ccm_ccgr6.cg13_reserved		= 0;
-	ccm_ccgr6.cg14_reserved		= 0;
-	ccm_ccgr6.cg15_reserved		= 0;
-	
-		// write register
-	eim_write_32(CCM_CCGR6, (uint32_t *)&ccm_ccgr6);
-}
-
-
-//------------------------------------------------------------------------------
-void _eim_setup_eim()
-//------------------------------------------------------------------------------
-{
-		// create structures
-	struct EIM_CS_GCR1	gcr1;
-	struct EIM_CS_GCR2	gcr2;
-	struct EIM_CS_RCR1	rcr1;
-	struct EIM_CS_RCR2	rcr2;
-	struct EIM_CS_WCR1	wcr1;
-	struct EIM_CS_WCR2	wcr2;
-	
-	struct EIM_WCR		wcr;
-	struct EIM_WIAR		wiar;
-	struct EIM_EAR		ear;
-	
-		// read all the registers
-	eim_read_32(EIM_CS0GCR1, (uint32_t *)&gcr1);
-	eim_read_32(EIM_CS0GCR2, (uint32_t *)&gcr2);
-	eim_read_32(EIM_CS0RCR1, (uint32_t *)&rcr1);
-	eim_read_32(EIM_CS0RCR2, (uint32_t *)&rcr2);
-	eim_read_32(EIM_CS0WCR1, (uint32_t *)&wcr1);
-	eim_read_32(EIM_CS0WCR2, (uint32_t *)&wcr2);
-	
-	eim_read_32(EIM_WCR,	(uint32_t *)&wcr);
-	eim_read_32(EIM_WIAR,	(uint32_t *)&wiar);
-	eim_read_32(EIM_EAR,	(uint32_t *)&ear);
-	
-		// manipulate registers as needed
-	gcr1.csen				= 1;	// chip select is enabled					|
-	gcr1.swr				= 1;	// write is sync							|
-	gcr1.srd				= 1;	// read is sync								|
-	gcr1.mum				= 1;	// address and data are multiplexed			|
-	gcr1.wfl				= 0;	// write latency is not fixed				|
-	gcr1.rfl				= 0;	// read latency is not fixed				|
-	gcr1.cre				= 0;	// CRE signal not needed					|
-	//gcr1.crep				= x;	// don't care, CRE not used					|
-	gcr1.bl					= 4;	// burst length 							| ?
-	gcr1.wc					= 0;	// write is not continuous 				 	| ?
-	gcr1.bcd				= 3;	// BCLK divisor is 3+1=4					|
-	gcr1.bcs				= 1;	// delay from ~CS to BCLK is 1 cycle		|
-	gcr1.dsz				= 1;	// 16 bits per databeat at DATA[15:0]		|
-	gcr1.sp					= 0;	// supervisor protection is disabled		|
-	gcr1.csrec				= 1;	// ~CS recovery is 1 cycle 					|
-	gcr1.aus				= 1;	// address is not shifted 					|
-	gcr1.gbc				= 1;	// ~CS gap is 1 cycle						|
-	gcr1.wp					= 0;	// write protection is not enabled			|
-	//gcr1.psz				= x;	// don't care, page mode is not used		|
-	
-	gcr2.adh				= 0;	// address hold duration is 1 cycle			|
-	//gcr2.daps				= x;	// don't care, DTACK is not used			|
-	gcr2.dae				= 0;	// DTACK is not used						|
-	//gcr2.dap				= x;	// don't care, DTACK is not used			|
-	gcr2.mux16_byp_grant	= 1;	// enable grant mechanism 					| ?
-	gcr2.reserved_3_2		= 0;	// must be 0								|
-	gcr2.reserved_11_10		= 0;	// must be 0								|
-	gcr2.reserved_31_13		= 0;	// must be 0								|
-	
-	//rcr1.rcsn				= x;	// don't care in sync mode					|
-	rcr1.rcsa				= 0;	// no delay for ~CS needed					|
-	//rcr1.oen				= x;	// don't care in sync mode					|
-	rcr1.oea				= 0;	// no delay for ~OE needed					|
-	rcr1.radvn				= 0;	// no delay for ~LBA needed					|
-	rcr1.ral				= 0;	// clear ~LBA when needed					|
-	rcr1.radva				= 0;	// no delay for ~LBA needed					|
-	rcr1.rwsc				= 1;	// one wait state							|
-	rcr1.reserved_3			= 0;	// must be 0								|
-	rcr1.reserved_7			= 0;	// must be 0								|
-	rcr1.reserved_11		= 0;	// must be 0								|
-	rcr1.reserved_15		= 0;	// must be 0								|
-	rcr1.reserved_23		= 0;	// must be 0								|
-	rcr1.reserved_31_30		= 0;	// must be 0								|
-	
-	//rcr2.rben				= x;	// don't care in sync mode					|
-	rcr2.rbe				= 0;	// BE is disabled							|
-	//rcr2.rbea				= x;	// don't care when BE is not used			|
-	rcr2.rl					= 0;	// read latency is 0 						| ?
-	//rcr2.pat				= x;	// don't care when page read is not used	|
-	rcr2.apr				= 0;	// page read mode is not used				|
-	rcr2.reserved_7			= 0;	// must be 0								|
-	rcr2.reserved_11_10		= 0;	// must be 0								|
-	rcr2.reserved_31_16		= 0;	// must be 0								|
-
-	//wcr1.wcsn				= x;	// don't care in sync mode					|
-	wcr1.wcsa				= 0;	// no delay for ~CS needed					|
-	//wcr1.wen				= x;	// don't care in sync mode					|
-	wcr1.wea				= 0;	// no delay for ~WR_N needed				|
-	//wcr1.wben				= x;	// don't care in sync mode					|
-	//wcr1.wbea				= x;	// don't care in sync mode					|
-	wcr1.wadvn				= 0;	// no delay for ~LBA needed					|
-	wcr1.wadva				= 0;	// no delay for ~LBA needed					|
-	wcr1.wwsc				= 1;	// no wait state in needed					|
-	wcr1.wbed				= 1;	// BE is disabled							|
-	wcr1.wal				= 0;	// clear ~LBA when needed					|
-
-	wcr2.wbcdd				= 0;	// write clock division is not needed		|
-	wcr2.reserved_31_1		= 0;	// must be 0								|
-	
-	wcr.bcm					= 0;	// clock is only active during access		|
-	//wcr.gbcd				= x;	// don't care when BCM=0					|
-	wcr.inten				= 0;	// interrupt is not used					|
-	//wcr.intpol			= x;	// don't care when interrupt is not used	|
-	wcr.wdog_en				= 1;	// watchdog is enabled						|
-	wcr.wdog_limit			= 00;	// timeout is 128 BCLK cycles				|
-	wcr.reserved_3			= 0;	// must be 0								|		
-	wcr.reserved_7_6		= 0;	// must be 0								|
-	wcr.reserved_31_11		= 0;	// must be 0								|
-	
-	wiar.ips_req			= 0;	// IPS not needed							|
-	wiar.ips_ack			= 0;	// IPS not needed							|
-	//wiar.irq				= x;	// don't touch								|
-	//wiar.errst			= x;	// don't touch								|
-	wiar.aclk_en			= 1;	// clock is enabled							|
-	wiar.reserved_31_5		= 0;	// must be 0								|
-	
-	//ear.error_addr		= x;	// read-only								|
-	
-		// write modified registers
-	eim_write_32(EIM_CS0GCR1,	(uint32_t *)&gcr1);
-	eim_write_32(EIM_CS0GCR2,	(uint32_t *)&gcr2);
-	eim_write_32(EIM_CS0RCR1,	(uint32_t *)&rcr1);
-	eim_write_32(EIM_CS0RCR2,	(uint32_t *)&rcr2);
-	eim_write_32(EIM_CS0WCR1,	(uint32_t *)&wcr1);
-	eim_write_32(EIM_CS0WCR2,	(uint32_t *)&wcr2);
-	eim_write_32(EIM_WCR,		(uint32_t *)&wcr);
-	eim_write_32(EIM_WIAR,	(uint32_t *)&wiar);/*
-	eim_write_32(EIM_EAR,		(uint32_t *)&ear);*/
-}
-
-
-//------------------------------------------------------------------------------
-void eim_write_32(off_t offset, uint32_t *pvalue)
-//------------------------------------------------------------------------------
-{
-		// calculate memory offset
-	uint32_t *ptr = (uint32_t *)_eim_calc_offset(offset);
-	
-		// write data to memory
-	memcpy(ptr, pvalue, sizeof(uint32_t));	
-}
-
-//------------------------------------------------------------------------------
-void eim_read_32(off_t offset, uint32_t *pvalue)
-//------------------------------------------------------------------------------
-{
-		// calculate memory offset
-	uint32_t *ptr = (uint32_t *)_eim_calc_offset(offset);
-	
-		// read data from memory
-	memcpy(pvalue, ptr, sizeof(uint32_t));	
-}
-
-
-//------------------------------------------------------------------------------
-off_t _eim_calc_offset(off_t offset)
-//------------------------------------------------------------------------------
-{
-		// make sure that memory is mapped
-	if (mem_map_ptr == MAP_FAILED) _eim_remap_mem(offset);
-
-		// calculate starting and ending addresses of currently mapped page
-	off_t offset_low	= mem_base_addr;
-	off_t offset_high	= mem_base_addr + (mem_page_size - 1);
-	
-		// check that offset is in currently mapped page, remap new page otherwise
-	if ((offset < offset_low) || (offset > offset_high)) _eim_remap_mem(offset);
-	
-		// calculate pointer
-	return (off_t)mem_map_ptr + (offset - mem_base_addr);
-}
-
-
-//------------------------------------------------------------------------------
-void _eim_remap_mem(off_t offset)
-//------------------------------------------------------------------------------
-{
-		// unmap old memory page if needed
-	if (mem_map_ptr != MAP_FAILED)
-	{	int ok = munmap(mem_map_ptr, mem_page_size);
-		if (ok != 0)
-		{	printf("ERROR: munmap() failed.\n");
-			exit(EXIT_FAILURE);
-		}
-	}
-	
-		// calculate starting address of new page
-	while (offset % mem_page_size) offset--;
-	
-		// try to map new memory page
-	mem_map_ptr = mmap(NULL, mem_page_size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_dev_fd, offset);
-	if (mem_map_ptr == MAP_FAILED)
-	{	printf("ERROR: mmap() failed.\n");
-		exit(EXIT_FAILURE);
-	}
-	
-		// save last mapped page address
-	mem_base_addr = offset;
-}
-
-
-//------------------------------------------------------------------------------
-// End-of-File
-//------------------------------------------------------------------------------
+/* 
+ * novena-eim.c
+ * ------------
+ * This module contains the userland magic to set up and use the EIM bus.
+ *
+ * 
+ * Author: Pavel Shatov
+ * Copyright (c) 2014-2015, NORDUnet A/S All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/mman.h>
+
+#include "novena-eim.h"
+
+
+//------------------------------------------------------------------------------
+// Defines
+//------------------------------------------------------------------------------
+#define MEMORY_DEVICE   "/dev/mem"
+
+#define IOMUXC_MUX_MODE_ALT0                    0       // 000
+
+#define IOMUXC_PAD_CTL_SRE_FAST                 1       // 1
+#define IOMUXC_PAD_CTL_DSE_33_OHM               7       // 111
+#define IOMUXC_PAD_CTL_SPEED_MEDIUM_10          2       // 10
+#define IOMUXC_PAD_CTL_ODE_DISABLED             0       // 0
+#define IOMUXC_PAD_CTL_PKE_DISABLED             0       // 0
+#define IOMUXC_PAD_CTL_PUE_PULL                 1       // 1
+#define IOMUXC_PAD_CTL_PUS_100K_OHM_PU          2       // 10
+#define IOMUXC_PAD_CTL_HYS_DISABLED             0       // 0
+
+#define CCM_CGR_OFF                             0       // 00
+#define CCM_CGR_ON_EXCEPT_STOP                  3       // 11
+
+
+//------------------------------------------------------------------------------
+// CPU Registers
+//------------------------------------------------------------------------------
+enum IMX6DQ_REGISTER_OFFSET
+{
+        IOMUXC_SW_MUX_CTL_PAD_EIM_CS0_B         = 0x020E00F8,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_OE_B          = 0x020E0100,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_RW            = 0x020E0104,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_LBA_B         = 0x020E0108,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD00          = 0x020E0114,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD01          = 0x020E0118,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD02          = 0x020E011C,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD03          = 0x020E0120,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD04          = 0x020E0124,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD05          = 0x020E0128,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD06          = 0x020E012C,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD07          = 0x020E0130,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD08          = 0x020E0134,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD09          = 0x020E0138,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD10          = 0x020E013C,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD11          = 0x020E0140,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD12          = 0x020E0144,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD13          = 0x020E0148,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD14          = 0x020E014C,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD15          = 0x020E0150,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_WAIT_B        = 0x020E0154,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_BCLK          = 0x020E0158,
+
+        IOMUXC_SW_PAD_CTL_PAD_EIM_CS0_B         = 0x020E040C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_OE_B          = 0x020E0414,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_RW            = 0x020E0418,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_LBA_B         = 0x020E041C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD00          = 0x020E0428,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD01          = 0x020E042C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD02          = 0x020E0430,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD03          = 0x020E0434,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD04          = 0x020E0438,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD05          = 0x020E043C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD06          = 0x020E0440,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD07          = 0x020E0444,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD08          = 0x020E0448,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD09          = 0x020E044C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD10          = 0x020E0450,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD11          = 0x020E0454,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD12          = 0x020E0458,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD13          = 0x020E045C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD14          = 0x020E0460,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD15          = 0x020E0464,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_WAIT_B        = 0x020E0468,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_BCLK          = 0x020E046C,
+        
+        CCM_CCGR6                               = 0x020C4080,
+        
+        EIM_CS0GCR1                             = 0x021B8000,
+        EIM_CS0GCR2                             = 0x021B8004,
+        EIM_CS0RCR1                             = 0x021B8008,
+        EIM_CS0RCR2                             = 0x021B800C,
+        EIM_CS0WCR1                             = 0x021B8010,
+        EIM_CS0WCR2                             = 0x021B8014,
+
+        EIM_WCR                                 = 0x021B8090,
+        EIM_WIAR                                = 0x021B8094,
+        EIM_EAR                                 = 0x021B8098,
+        
+};
+
+
+//------------------------------------------------------------------------------
+// Structures
+//------------------------------------------------------------------------------
+struct IOMUXC_SW_MUX_CTL_PAD_EIM
+{
+        uint32_t        mux_mode                :  3;
+        uint32_t        reserved_3              :  1;
+        uint32_t        sion                    :  1;
+        uint32_t        reserved_31_5           : 27;
+};
+
+struct IOMUXC_SW_PAD_CTL_PAD_EIM
+{
+        uint32_t        sre                     : 1;
+        uint32_t        reserved_2_1            : 2;
+        uint32_t        dse                     : 3;
+        uint32_t        speed                   : 2;
+        uint32_t        reserved_10_8           : 3;
+        uint32_t        ode                     : 1;
+        uint32_t        pke                     : 1;
+        uint32_t        pue                     : 1;
+        uint32_t        pus                     : 2;
+        uint32_t        hys                     : 1;
+        uint32_t        reserved_31_17          : 15;
+};
+
+struct CCM_CCGR6
+{
+        uint32_t        cg0_usboh3              : 2;
+        uint32_t        cg1_usdhc1              : 2;
+        uint32_t        cg2_usdhc2              : 2;
+        uint32_t        cg3_usdhc3              : 2;
+        
+        uint32_t        cg3_usdhc4              : 2;
+        uint32_t        cg5_eim_slow            : 2;
+        uint32_t        cg6_vdoaxiclk           : 2;
+        uint32_t        cg7_vpu                 : 2;
+        
+        uint32_t        cg8_reserved            : 2;
+        uint32_t        cg9_reserved            : 2;
+        uint32_t        cg10_reserved           : 2;
+        uint32_t        cg11_reserved           : 2;
+        
+        uint32_t        cg12_reserved           : 2;
+        uint32_t        cg13_reserved           : 2;
+        uint32_t        cg14_reserved           : 2;
+        uint32_t        cg15_reserved           : 2;
+};
+
+struct EIM_CS_GCR1
+{
+        uint32_t        csen                    : 1;
+        uint32_t        swr                     : 1;
+        uint32_t        srd                     : 1;
+        uint32_t        mum                     : 1;
+        uint32_t        wfl                     : 1;
+        uint32_t        rfl                     : 1;
+        uint32_t        cre                     : 1;
+        uint32_t        crep                    : 1;
+        uint32_t        bl                      : 3;
+        uint32_t        wc                      : 1;
+        uint32_t        bcd                     : 2;
+        uint32_t        bcs                     : 2;
+        uint32_t        dsz                     : 3;
+        uint32_t        sp                      : 1;
+        uint32_t        csrec                   : 3;
+        uint32_t        aus                     : 1;
+        uint32_t        gbc                     : 3;
+        uint32_t        wp                      : 1;
+        uint32_t        psz                     : 4;
+};
+
+struct EIM_CS_GCR2
+{
+        uint32_t        adh                     :  2;
+        uint32_t        reserved_3_2            :  2;
+        uint32_t        daps                    :  4;
+        uint32_t        dae                     :  1;
+        uint32_t        dap                     :  1;
+        uint32_t        reserved_11_10          :  2;
+        uint32_t        mux16_byp_grant         :  1;
+        uint32_t        reserved_31_13          : 19;
+};
+
+struct EIM_CS_RCR1
+{
+        uint32_t        rcsn                    : 3;
+        uint32_t        reserved_3              : 1;
+        uint32_t        rcsa                    : 3;
+        uint32_t        reserved_7              : 1;
+        uint32_t        oen                     : 3;
+        uint32_t        reserved_11             : 1;
+        uint32_t        oea                     : 3;
+        uint32_t        reserved_15             : 1;
+        uint32_t        radvn                   : 3;
+        uint32_t        ral                     : 1;
+        uint32_t        radva                   : 3;
+        uint32_t        reserved_23             : 1;
+        uint32_t        rwsc                    : 6;
+        uint32_t        reserved_31_30          : 2;
+};
+
+struct EIM_CS_RCR2
+{
+        uint32_t        rben                    :  3;
+        uint32_t        rbe                     :  1;
+        uint32_t        rbea                    :  3;
+        uint32_t        reserved_7              :  1;
+        uint32_t        rl                      :  2;
+        uint32_t        reserved_11_10          :  2;
+        uint32_t        pat                     :  3;
+        uint32_t        apr                     :  1;
+        uint32_t        reserved_31_16          : 16;
+};
+
+struct EIM_CS_WCR1
+{
+        uint32_t        wcsn                    : 3;
+        uint32_t        wcsa                    : 3;
+        uint32_t        wen                     : 3;
+        uint32_t        wea                     : 3;
+        uint32_t        wben                    : 3;
+        uint32_t        wbea                    : 3;
+        uint32_t        wadvn                   : 3;
+        uint32_t        wadva                   : 3;
+        uint32_t        wwsc                    : 6;
+        uint32_t        wbed                    : 1;
+        uint32_t        wal                     : 1;
+};
+
+struct EIM_CS_WCR2
+{
+        uint32_t        wbcdd                   :  1;
+        uint32_t        reserved_31_1           : 31;
+};
+
+struct EIM_WCR
+{
+        uint32_t        bcm                     :  1;
+        uint32_t        gbcd                    :  2;
+        uint32_t        reserved_3              :  1;
+        uint32_t        inten                   :  1;
+        uint32_t        intpol                  :  1;
+        uint32_t        reserved_7_6            :  2;
+        uint32_t        wdog_en                 :  1;
+        uint32_t        wdog_limit              :  2;
+        uint32_t        reserved_31_11          : 21;
+};
+
+struct EIM_WIAR
+{
+        uint32_t        ips_req                 :  1;
+        uint32_t        ips_ack                 :  1;
+        uint32_t        irq                     :  1;
+        uint32_t        errst                   :  1;
+        uint32_t        aclk_en                 :  1;
+        uint32_t        reserved_31_5           : 27;
+};
+
+struct EIM_EAR
+{
+        uint32_t        error_addr              : 32;
+};
+
+
+//------------------------------------------------------------------------------
+// Variables
+//------------------------------------------------------------------------------
+static long     mem_page_size   = 0;
+static int      mem_dev_fd      = -1;
+static void *   mem_map_ptr     = MAP_FAILED;
+static off_t    mem_base_addr   = 0;
+
+//------------------------------------------------------------------------------
+// Prototypes
+//------------------------------------------------------------------------------
+static void     _eim_setup_iomuxc       (void);
+static void     _eim_setup_ccm          (void);
+static void     _eim_setup_eim          (void);
+static void     _eim_cleanup            (void);
+static off_t    _eim_calc_offset        (off_t);
+static void     _eim_remap_mem          (off_t);
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+int eim_setup(void)
+{
+    // register cleanup function
+    if (atexit(_eim_cleanup) != 0) {
+        fprintf(stderr, "ERROR: atexit() failed.\n");
+        return -1;
+    }
+
+    // determine memory page size to use in mmap()
+    mem_page_size = sysconf(_SC_PAGESIZE);
+    if (mem_page_size < 1) {
+        fprintf(stderr, "ERROR: sysconf(_SC_PAGESIZE) == %ld\n", mem_page_size);
+        return -1;
+    }
+
+    // try to open memory device
+    mem_dev_fd = open(MEMORY_DEVICE, O_RDWR | O_SYNC);
+    if (mem_dev_fd == -1) {
+        fprintf(stderr, "ERROR: open(%s) failed.\n", MEMORY_DEVICE);
+        return -1;
+    }
+
+    /* Several blocks in the CPU have common pins, we can use I/O MUX Controller
+     * to configure what block will actually use I/O pins. We wait EIM module to be able
+     * to communicate with the on-board FPGA. Let's configure IOMUXC accordingly.
+     */
+    _eim_setup_iomuxc();
+
+    /* We need to enable clocking of EIM block in order to be able to use it.
+     * Let's configure Clock Controller Module accordingly.
+     */
+    _eim_setup_ccm();
+
+    /* We need to properly configure EIM mode and all the corresponding parameters.
+     * That's a lot of code, let's do it now.
+     */
+    _eim_setup_eim();
+
+    // done
+    return 0;
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+static void _eim_cleanup(void)
+{
+    // unmap memory if needed
+    if (mem_map_ptr != MAP_FAILED)
+        if (munmap(mem_map_ptr, mem_page_size) != 0)
+            fprintf(stderr, "WARNING: munmap() failed.\n");
+
+    // close memory device if needed
+    if (mem_dev_fd != -1)
+        if (close(mem_dev_fd) != 0)
+            fprintf(stderr, "WARNING: close() failed.\n");
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+static void _eim_setup_iomuxc(void)
+{
+    // create structures
+    struct IOMUXC_SW_MUX_CTL_PAD_EIM    reg_mux;                        // mux control register
+    struct IOMUXC_SW_PAD_CTL_PAD_EIM    reg_pad;                        // pad control register
+
+    // setup mux control register
+    reg_mux.mux_mode            = IOMUXC_MUX_MODE_ALT0;                 // ALT0 mode must be used for EIM
+    reg_mux.sion                = 0;                                    // forced input not needed
+    reg_mux.reserved_3          = 0;                                    // must be 0
+    reg_mux.reserved_31_5       = 0;                                    // must be 0
+
+    // setup pad control register
+    reg_pad.sre                 = IOMUXC_PAD_CTL_SRE_FAST;              // fast slew rate
+    reg_pad.dse                 = IOMUXC_PAD_CTL_DSE_33_OHM;            // highest drive strength
+    reg_pad.speed               = IOMUXC_PAD_CTL_SPEED_MEDIUM_10;       // medium speed
+    reg_pad.ode                 = IOMUXC_PAD_CTL_ODE_DISABLED;          // open drain not needed
+    reg_pad.pke                 = IOMUXC_PAD_CTL_PKE_DISABLED;          // neither pull nor keeper are needed
+    reg_pad.pue                 = IOMUXC_PAD_CTL_PUE_PULL;              // doesn't matter actually, because PKE is disabled
+    reg_pad.pus                 = IOMUXC_PAD_CTL_PUS_100K_OHM_PU;       // doesn't matter actually, because PKE is disabled
+    reg_pad.hys                 = IOMUXC_PAD_CTL_HYS_DISABLED;          // use CMOS, not Schmitt trigger input
+    reg_pad.reserved_2_1        = 0;                                    // must be 0
+    reg_pad.reserved_10_8       = 0;                                    // must be 0
+    reg_pad.reserved_31_17      = 0;                                    // must be 0
+
+    // all the pins must be configured to use the same ALT0 mode
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_CS0_B,       (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_OE_B,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_RW,          (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_LBA_B,       (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD00,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD01,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD02,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD03,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD04,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD05,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD06,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD07,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD08,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD09,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD10,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD11,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD12,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD13,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD14,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD15,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_WAIT_B,      (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_BCLK,        (uint32_t *)&reg_mux);
+
+    // we need to configure all the I/O pads too
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_CS0_B,       (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_OE_B,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_RW,          (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_LBA_B,       (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD00,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD01,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD02,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD03,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD04,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD05,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD06,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD07,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD08,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD09,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD10,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD11,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD12,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD13,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD14,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD15,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_WAIT_B,      (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_BCLK,        (uint32_t *)&reg_pad);
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+static void _eim_setup_ccm(void)
+{
+    // create structure
+    struct CCM_CCGR6 ccm_ccgr6;
+
+    // read register
+    eim_read_32(CCM_CCGR6, (uint32_t *)&ccm_ccgr6);
+
+    // modify register
+    ccm_ccgr6.cg0_usboh3                = CCM_CGR_ON_EXCEPT_STOP;
+    ccm_ccgr6.cg1_usdhc1                = CCM_CGR_OFF;
+    ccm_ccgr6.cg2_usdhc2                = CCM_CGR_ON_EXCEPT_STOP;
+    ccm_ccgr6.cg3_usdhc3                = CCM_CGR_ON_EXCEPT_STOP;
+
+    ccm_ccgr6.cg3_usdhc4                = CCM_CGR_OFF;
+    ccm_ccgr6.cg5_eim_slow              = CCM_CGR_ON_EXCEPT_STOP;
+    ccm_ccgr6.cg6_vdoaxiclk             = CCM_CGR_OFF;
+    ccm_ccgr6.cg7_vpu                   = CCM_CGR_OFF;
+
+    ccm_ccgr6.cg8_reserved              = 0;
+    ccm_ccgr6.cg9_reserved              = 0;
+    ccm_ccgr6.cg10_reserved             = 0;
+    ccm_ccgr6.cg11_reserved             = 0;
+    ccm_ccgr6.cg12_reserved             = 0;
+    ccm_ccgr6.cg13_reserved             = 0;
+    ccm_ccgr6.cg14_reserved             = 0;
+    ccm_ccgr6.cg15_reserved             = 0;
+
+    // write register
+    eim_write_32(CCM_CCGR6, (uint32_t *)&ccm_ccgr6);
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+static void _eim_setup_eim(void)
+{
+    // create structures
+    struct EIM_CS_GCR1  gcr1;
+    struct EIM_CS_GCR2  gcr2;
+    struct EIM_CS_RCR1  rcr1;
+    struct EIM_CS_RCR2  rcr2;
+    struct EIM_CS_WCR1  wcr1;
+    struct EIM_CS_WCR2  wcr2;
+
+    struct EIM_WCR              wcr;
+    struct EIM_WIAR             wiar;
+    struct EIM_EAR              ear;
+
+    // read all the registers
+    eim_read_32(EIM_CS0GCR1, (uint32_t *)&gcr1);
+    eim_read_32(EIM_CS0GCR2, (uint32_t *)&gcr2);
+    eim_read_32(EIM_CS0RCR1, (uint32_t *)&rcr1);
+    eim_read_32(EIM_CS0RCR2, (uint32_t *)&rcr2);
+    eim_read_32(EIM_CS0WCR1, (uint32_t *)&wcr1);
+    eim_read_32(EIM_CS0WCR2, (uint32_t *)&wcr2);
+
+    eim_read_32(EIM_WCR,        (uint32_t *)&wcr);
+    eim_read_32(EIM_WIAR,       (uint32_t *)&wiar);
+    eim_read_32(EIM_EAR,        (uint32_t *)&ear);
+
+    // manipulate registers as needed
+    gcr1.csen           = 1;    // chip select is enabled
+    gcr1.swr            = 1;    // write is sync
+    gcr1.srd            = 1;    // read is sync
+    gcr1.mum            = 1;    // address and data are multiplexed
+    gcr1.wfl            = 0;    // write latency is not fixed
+    gcr1.rfl            = 0;    // read latency is not fixed
+    gcr1.cre            = 0;    // CRE signal not needed
+    //gcr1.crep         = x;    // don't care, CRE not used
+    gcr1.bl             = 4;    // burst length
+    gcr1.wc             = 0;    // write is not continuous
+    gcr1.bcd            = 3;    // BCLK divisor is 3+1=4
+    gcr1.bcs            = 1;    // delay from ~CS to BCLK is 1 cycle
+    gcr1.dsz            = 1;    // 16 bits per databeat at DATA[15:0]
+    gcr1.sp             = 0;    // supervisor protection is disabled
+    gcr1.csrec          = 1;    // ~CS recovery is 1 cycle
+    gcr1.aus            = 1;    // address is not shifted
+    gcr1.gbc            = 1;    // ~CS gap is 1 cycle
+    gcr1.wp             = 0;    // write protection is not enabled
+    //gcr1.psz          = x;    // don't care, page mode is not used
+
+    gcr2.adh            = 0;    // address hold duration is 1 cycle
+    //gcr2.daps         = x;    // don't care, DTACK is not used
+    gcr2.dae            = 0;    // DTACK is not used
+    //gcr2.dap          = x;    // don't care, DTACK is not used
+    gcr2.mux16_byp_grant= 1;    // enable grant mechanism
+    gcr2.reserved_3_2   = 0;    // must be 0
+    gcr2.reserved_11_10 = 0;    // must be 0
+    gcr2.reserved_31_13 = 0;    // must be 0
+
+    //rcr1.rcsn         = x;    // don't care in sync mode
+    rcr1.rcsa           = 0;    // no delay for ~CS needed
+    //rcr1.oen          = x;    // don't care in sync mode
+    rcr1.oea            = 0;    // no delay for ~OE needed
+    rcr1.radvn          = 0;    // no delay for ~LBA needed
+    rcr1.ral            = 0;    // clear ~LBA when needed
+    rcr1.radva          = 0;    // no delay for ~LBA needed
+    rcr1.rwsc           = 1;    // one wait state
+    rcr1.reserved_3     = 0;    // must be 0
+    rcr1.reserved_7     = 0;    // must be 0
+    rcr1.reserved_11    = 0;    // must be 0
+    rcr1.reserved_15    = 0;    // must be 0
+    rcr1.reserved_23    = 0;    // must be 0
+    rcr1.reserved_31_30 = 0;    // must be 0
+
+    //rcr2.rben         = x;    // don't care in sync mode
+    rcr2.rbe            = 0;    // BE is disabled
+    //rcr2.rbea         = x;    // don't care when BE is not used
+    rcr2.rl             = 0;    // read latency is 0
+    //rcr2.pat          = x;    // don't care when page read is not used
+    rcr2.apr            = 0;    // page read mode is not used
+    rcr2.reserved_7     = 0;    // must be 0
+    rcr2.reserved_11_10 = 0;    // must be 0
+    rcr2.reserved_31_16 = 0;    // must be 0
+
+    //wcr1.wcsn         = x;    // don't care in sync mode
+    wcr1.wcsa           = 0;    // no delay for ~CS needed
+    //wcr1.wen          = x;    // don't care in sync mode
+    wcr1.wea            = 0;    // no delay for ~WR_N needed
+    //wcr1.wben         = x;    // don't care in sync mode
+    //wcr1.wbea         = x;    // don't care in sync mode
+    wcr1.wadvn          = 0;    // no delay for ~LBA needed
+    wcr1.wadva          = 0;    // no delay for ~LBA needed
+    wcr1.wwsc           = 1;    // no wait state in needed
+    wcr1.wbed           = 1;    // BE is disabled
+    wcr1.wal            = 0;    // clear ~LBA when needed
+
+    wcr2.wbcdd          = 0;    // write clock division is not needed
+    wcr2.reserved_31_1  = 0;    // must be 0
+
+    wcr.bcm             = 0;    // clock is only active during access
+    //wcr.gbcd          = x;    // don't care when BCM=0
+    wcr.inten           = 0;    // interrupt is not used
+    //wcr.intpol        = x;    // don't care when interrupt is not used
+    wcr.wdog_en         = 1;    // watchdog is enabled
+    wcr.wdog_limit      = 00;   // timeout is 128 BCLK cycles
+    wcr.reserved_3      = 0;    // must be 0
+    wcr.reserved_7_6    = 0;    // must be 0
+    wcr.reserved_31_11  = 0;    // must be 0
+
+    wiar.ips_req        = 0;    // IPS not needed
+    wiar.ips_ack        = 0;    // IPS not needed
+    //wiar.irq          = x;    // don't touch
+    //wiar.errst        = x;    // don't touch
+    wiar.aclk_en        = 1;    // clock is enabled
+    wiar.reserved_31_5  = 0;    // must be 0
+
+    //ear.error_addr    = x;    // read-only
+
+    // write modified registers
+    eim_write_32(EIM_CS0GCR1,   (uint32_t *)&gcr1);
+    eim_write_32(EIM_CS0GCR2,   (uint32_t *)&gcr2);
+    eim_write_32(EIM_CS0RCR1,   (uint32_t *)&rcr1);
+    eim_write_32(EIM_CS0RCR2,   (uint32_t *)&rcr2);
+    eim_write_32(EIM_CS0WCR1,   (uint32_t *)&wcr1);
+    eim_write_32(EIM_CS0WCR2,   (uint32_t *)&wcr2);
+    eim_write_32(EIM_WCR,               (uint32_t *)&wcr);
+    eim_write_32(EIM_WIAR,      (uint32_t *)&wiar);
+/*  eim_write_32(EIM_EAR,       (uint32_t *)&ear);*/
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+void eim_write_32(off_t offset, uint32_t *pvalue)
+{
+    // calculate memory offset
+    uint32_t *ptr = (uint32_t *)_eim_calc_offset(offset);
+
+    // write data to memory
+    memcpy(ptr, pvalue, sizeof(uint32_t));
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+void eim_read_32(off_t offset, uint32_t *pvalue)
+{
+    // calculate memory offset
+    uint32_t *ptr = (uint32_t *)_eim_calc_offset(offset);
+
+    // read data from memory
+    memcpy(pvalue, ptr, sizeof(uint32_t));
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+static off_t _eim_calc_offset(off_t offset)
+{
+    // make sure that memory is mapped
+    if (mem_map_ptr == MAP_FAILED)
+        _eim_remap_mem(offset);
+
+    // calculate starting and ending addresses of currently mapped page
+    off_t offset_low    = mem_base_addr;
+    off_t offset_high   = mem_base_addr + (mem_page_size - 1);
+
+    // check that offset is in currently mapped page, remap new page otherwise
+    if ((offset < offset_low) || (offset > offset_high))
+        _eim_remap_mem(offset);
+
+    // calculate pointer
+    return (off_t)mem_map_ptr + (offset - mem_base_addr);
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+static void _eim_remap_mem(off_t offset)
+{
+    // unmap old memory page if needed
+    if (mem_map_ptr != MAP_FAILED) {
+        if (munmap(mem_map_ptr, mem_page_size) != 0) {
+            fprintf(stderr, "ERROR: munmap() failed.\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    // calculate starting address of new page
+    while (offset % mem_page_size)
+        offset--;
+
+    // try to map new memory page
+    mem_map_ptr = mmap(NULL, mem_page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                       mem_dev_fd, offset);
+    if (mem_map_ptr == MAP_FAILED) {
+        fprintf(stderr, "ERROR: mmap() failed.\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // save last mapped page address
+    mem_base_addr = offset;
+}
+
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/sw/novena-eim.h b/sw/novena-eim.h
index 3d29f77..75613bf 100644
--- a/sw/novena-eim.h
+++ b/sw/novena-eim.h
@@ -1,297 +1,52 @@
-//------------------------------------------------------------------------------
-// novena-eim.h
-//------------------------------------------------------------------------------
-
-
-//------------------------------------------------------------------------------
-// Defined Values
-//------------------------------------------------------------------------------
-#define MEMORY_DEVICE	"/dev/mem"
-
-
-//------------------------------------------------------------------------------
-// IOMUXC Values
-//------------------------------------------------------------------------------
-#define IOMUXC_MUX_MODE_ALT0			0	// 000
-
-#define IOMUXC_PAD_CTL_SRE_FAST			1	// 1
-#define IOMUXC_PAD_CTL_DSE_33_OHM		7	// 111
-#define IOMUXC_PAD_CTL_SPEED_MEDIUM_10	2	// 10
-#define IOMUXC_PAD_CTL_ODE_DISABLED		0	// 0
-#define IOMUXC_PAD_CTL_PKE_DISABLED		0	// 0
-#define IOMUXC_PAD_CTL_PUE_PULL			1	// 1
-#define IOMUXC_PAD_CTL_PUS_100K_OHM_PU	2	// 10
-#define IOMUXC_PAD_CTL_HYS_DISABLED		0	// 0
-
-//------------------------------------------------------------------------------
-// CCM Values
-//------------------------------------------------------------------------------
-#define CCM_CGR_OFF						0	// 00
-#define CCM_CGR_ON_EXCEPT_STOP			3	// 11
-
-
-//------------------------------------------------------------------------------
-// CPU Registers
-//------------------------------------------------------------------------------
-enum IMX6DQ_REGISTER_OFFSET
-{
-	IOMUXC_SW_MUX_CTL_PAD_EIM_CS0_B		= 0x020E00F8,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_OE_B		= 0x020E0100,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_RW		= 0x020E0104,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_LBA_B		= 0x020E0108,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD00		= 0x020E0114,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD01		= 0x020E0118,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD02		= 0x020E011C,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD03		= 0x020E0120,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD04		= 0x020E0124,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD05		= 0x020E0128,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD06		= 0x020E012C,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD07		= 0x020E0130,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD08		= 0x020E0134,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD09		= 0x020E0138,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD10		= 0x020E013C,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD11		= 0x020E0140,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD12		= 0x020E0144,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD13		= 0x020E0148,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD14		= 0x020E014C,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_AD15		= 0x020E0150,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_WAIT_B	= 0x020E0154,
-	IOMUXC_SW_MUX_CTL_PAD_EIM_BCLK		= 0x020E0158,
-
-	IOMUXC_SW_PAD_CTL_PAD_EIM_CS0_B		= 0x020E040C,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_OE_B		= 0x020E0414,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_RW		= 0x020E0418,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_LBA_B		= 0x020E041C,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD00		= 0x020E0428,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD01		= 0x020E042C,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD02		= 0x020E0430,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD03		= 0x020E0434,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD04		= 0x020E0438,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD05		= 0x020E043C,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD06		= 0x020E0440,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD07		= 0x020E0444,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD08		= 0x020E0448,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD09		= 0x020E044C,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD10		= 0x020E0450,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD11		= 0x020E0454,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD12		= 0x020E0458,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD13		= 0x020E045C,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD14		= 0x020E0460,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_AD15		= 0x020E0464,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_WAIT_B	= 0x020E0468,
-	IOMUXC_SW_PAD_CTL_PAD_EIM_BCLK		= 0x020E046C,
-	
-	CCM_CCGR6							= 0x020C4080,
-	
-	EIM_CS0GCR1							= 0x021B8000,
-	EIM_CS0GCR2							= 0x021B8004,
-	EIM_CS0RCR1							= 0x021B8008,
-	EIM_CS0RCR2							= 0x021B800C,
-	EIM_CS0WCR1							= 0x021B8010,
-	EIM_CS0WCR2							= 0x021B8014,
-
-	EIM_WCR								= 0x021B8090,
-	EIM_WIAR							= 0x021B8094,
-	EIM_EAR								= 0x021B8098,
-	
-	EIM_BASE_ADDR						= 0x08000000
-};
-
-
-//------------------------------------------------------------------------------
-struct IOMUXC_SW_MUX_CTL_PAD_EIM
-//------------------------------------------------------------------------------
-{
-	uint32_t	mux_mode			:  3;
-	uint32_t	reserved_3			:  1;
-	uint32_t	sion				:  1;
-	uint32_t	reserved_31_5		: 27;
-};
-//------------------------------------------------------------------------------
-struct IOMUXC_SW_PAD_CTL_PAD_EIM
-//------------------------------------------------------------------------------
-{
-	uint32_t	sre					: 1;
-	uint32_t	reserved_2_1		: 2;
-	uint32_t	dse					: 3;
-	uint32_t	speed				: 2;
-	uint32_t	reserved_10_8		: 3;
-	uint32_t	ode					: 1;
-	uint32_t	pke					: 1;
-	uint32_t	pue					: 1;
-	uint32_t	pus					: 2;
-	uint32_t	hys					: 1;
-	uint32_t	reserved_31_17		: 15;
-};
-
-
-//------------------------------------------------------------------------------
-struct CCM_CCGR6
-//------------------------------------------------------------------------------
-{
-	uint32_t	cg0_usboh3			: 2;
-	uint32_t	cg1_usdhc1			: 2;
-	uint32_t	cg2_usdhc2			: 2;
-	uint32_t	cg3_usdhc3			: 2;
-	
-	uint32_t	cg3_usdhc4			: 2;
-	uint32_t	cg5_eim_slow		: 2;
-	uint32_t	cg6_vdoaxiclk		: 2;
-	uint32_t	cg7_vpu				: 2;
-	
-	uint32_t	cg8_reserved		: 2;
-	uint32_t	cg9_reserved		: 2;
-	uint32_t	cg10_reserved		: 2;
-	uint32_t	cg11_reserved		: 2;
-	
-	uint32_t	cg12_reserved		: 2;
-	uint32_t	cg13_reserved		: 2;
-	uint32_t	cg14_reserved		: 2;
-	uint32_t	cg15_reserved		: 2;
-};
-
-
-//------------------------------------------------------------------------------
-struct EIM_CS_GCR1
-//------------------------------------------------------------------------------
-{
-	uint32_t	csen				: 1;
-	uint32_t	swr					: 1;
-	uint32_t	srd					: 1;
-	uint32_t	mum					: 1;
-	uint32_t	wfl					: 1;
-	uint32_t	rfl					: 1;
-	uint32_t	cre					: 1;
-	uint32_t	crep				: 1;
-	uint32_t	bl					: 3;
-	uint32_t	wc					: 1;
-	uint32_t	bcd					: 2;
-	uint32_t	bcs					: 2;
-	uint32_t	dsz					: 3;
-	uint32_t	sp					: 1;
-	uint32_t	csrec				: 3;
-	uint32_t	aus					: 1;
-	uint32_t	gbc					: 3;
-	uint32_t	wp					: 1;
-	uint32_t	psz					: 4;
-};
-//------------------------------------------------------------------------------
-struct EIM_CS_GCR2
-//------------------------------------------------------------------------------
-{
-	uint32_t	adh					:  2;
-	uint32_t 	reserved_3_2		:  2;
-	uint32_t	daps				:  4;
-	uint32_t	dae					:  1;
-	uint32_t	dap					:  1;
-	uint32_t	reserved_11_10		:  2;
-	uint32_t	mux16_byp_grant		:  1;
-	uint32_t	reserved_31_13		: 19;
-};
-//------------------------------------------------------------------------------
-struct EIM_CS_RCR1
-//------------------------------------------------------------------------------
-{
-	uint32_t	rcsn				: 3;
-	uint32_t	reserved_3			: 1;
-	uint32_t	rcsa				: 3;
-	uint32_t	reserved_7			: 1;
-	uint32_t	oen					: 3;
-	uint32_t	reserved_11			: 1;
-	uint32_t	oea					: 3;
-	uint32_t	reserved_15			: 1;
-	uint32_t	radvn				: 3;
-	uint32_t	ral					: 1;
-	uint32_t	radva				: 3;
-	uint32_t	reserved_23			: 1;
-	uint32_t	rwsc				: 6;
-	uint32_t	reserved_31_30		: 2;
-};
-//------------------------------------------------------------------------------
-struct EIM_CS_RCR2
-//------------------------------------------------------------------------------
-{
-	uint32_t	rben				:  3;
-	uint32_t	rbe					:  1;
-	uint32_t	rbea				:  3;
-	uint32_t	reserved_7			:  1;
-	uint32_t	rl					:  2;
-	uint32_t	reserved_11_10		:  2;
-	uint32_t	pat					:  3;
-	uint32_t	apr					:  1;
-	uint32_t	reserved_31_16		: 16;
-};
-//------------------------------------------------------------------------------
-struct EIM_CS_WCR1
-//------------------------------------------------------------------------------
-{
-	uint32_t	wcsn				: 3;
-	uint32_t 	wcsa				: 3;
-	uint32_t	wen					: 3;
-	uint32_t	wea					: 3;
-	uint32_t 	wben				: 3;
-	uint32_t	wbea				: 3;
-	uint32_t	wadvn				: 3;
-	uint32_t	wadva				: 3;
-	uint32_t	wwsc				: 6;
-	uint32_t	wbed				: 1;
-	uint32_t	wal					: 1;
-};
-//------------------------------------------------------------------------------
-struct EIM_CS_WCR2
-//------------------------------------------------------------------------------
-{
-	uint32_t	wbcdd				:  1;
-	uint32_t	reserved_31_1		: 31;
-};
-//------------------------------------------------------------------------------
-struct EIM_WCR
-//------------------------------------------------------------------------------
-{
-	uint32_t	bcm					:  1;
-	uint32_t	gbcd				:  2;
-	uint32_t	reserved_3			:  1;
-	uint32_t	inten				:  1;
-	uint32_t	intpol				:  1;
-	uint32_t	reserved_7_6		:  2;
-	uint32_t	wdog_en				:  1;
-	uint32_t	wdog_limit			:  2;
-	uint32_t	reserved_31_11		: 21;
-};
-//------------------------------------------------------------------------------
-struct EIM_WIAR
-//------------------------------------------------------------------------------
-{
-	uint32_t	ips_req				:  1;
-	uint32_t	ips_ack				:  1;
-	uint32_t	irq					:  1;
-	uint32_t	errst				:  1;
-	uint32_t	aclk_en				:  1;
-	uint32_t	reserved_31_5		: 27;
-};
-//------------------------------------------------------------------------------
-struct EIM_EAR
-//------------------------------------------------------------------------------
-{
-	uint32_t	error_addr			: 32;
-};
-
-
-//------------------------------------------------------------------------------
-// Prototypes
-//------------------------------------------------------------------------------
-int		eim_setup			();
-void	eim_write_32		(off_t, uint32_t *);
-void	eim_read_32			(off_t, uint32_t *);
-
-void	_eim_setup_iomuxc	();
-void	_eim_setup_ccm		();
-void	_eim_setup_eim		();
-void	_eim_cleanup		();
-off_t	_eim_calc_offset	(off_t);
-void	_eim_remap_mem		(off_t);
-
-
-//------------------------------------------------------------------------------
-// End-of-File
-//------------------------------------------------------------------------------
+/* 
+ * novena-eim.h
+ * ------------
+ * This module contains the userland magic to set up and use the EIM bus.
+ *
+ * 
+ * Author: Pavel Shatov
+ * Copyright (c) 2014-2015, NORDUnet A/S All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define EIM_BASE_ADDR 0x08000000
+
+/* Set up EIM bus.
+ * Returns 0 on success, -1 on failure.
+ */
+int  eim_setup(void);
+
+/* Write a 32-bit word to EIM.
+ * If EIM is not set up correctly, this will abort with a bus error.
+ */
+void eim_write_32(off_t, uint32_t *);
+
+/* Read a 32-bit word from EIM.
+ * If EIM is not set up correctly, this will abort with a bus error.
+ */
+void eim_read_32(off_t, uint32_t *);



More information about the Commits mailing list