test_mmio.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * c-periphery
  3. * https://github.com/vsergeev/c-periphery
  4. * License: MIT
  5. */
  6. #include "test.h"
  7. #include <stdlib.h>
  8. #include <unistd.h>
  9. #include <string.h>
  10. #include <time.h>
  11. #include "../src/mmio.h"
  12. #define PAGE_SIZE 4096
  13. #define CONTROL_MODULE_BASE 0x44e10000
  14. #define USB_VID_PID_OFFSET 0x7f4
  15. #define USB_VID_PID 0x04516141
  16. #define RTCSS_BASE 0x44e3e000
  17. #define RTC_SCRATCH2_REG_OFFSET 0x68
  18. void test_arguments(void) {
  19. ptest();
  20. /* Check offset out of bounds in test_open_config_close() */
  21. }
  22. void test_open_config_close(void) {
  23. mmio_t *mmio;
  24. uintptr_t address;
  25. uint32_t value32;
  26. ptest();
  27. /* Allocate MMIO */
  28. mmio = mmio_new();
  29. passert(mmio != NULL);
  30. /* Open aligned base */
  31. passert(mmio_open(mmio, CONTROL_MODULE_BASE, PAGE_SIZE) == 0);
  32. passert(mmio_base(mmio) == CONTROL_MODULE_BASE);
  33. passert(mmio_size(mmio) == PAGE_SIZE);
  34. passert(mmio_ptr(mmio) != NULL);
  35. struct mmio_handle {
  36. uintptr_t base, aligned_base;
  37. size_t size, aligned_size;
  38. void *ptr;
  39. struct {
  40. int c_errno;
  41. char errmsg[96];
  42. } error;
  43. };
  44. /* Check alignment math */
  45. passert(((struct mmio_handle *)mmio)->base == CONTROL_MODULE_BASE);
  46. passert(((struct mmio_handle *)mmio)->size == PAGE_SIZE);
  47. passert(((struct mmio_handle *)mmio)->aligned_base == CONTROL_MODULE_BASE);
  48. passert(((struct mmio_handle *)mmio)->aligned_size == PAGE_SIZE);
  49. passert(mmio_ptr(mmio) == ((struct mmio_handle *)mmio)->ptr);
  50. passert(mmio_read32(mmio, PAGE_SIZE-3, &value32) == MMIO_ERROR_ARG);
  51. passert(mmio_read32(mmio, PAGE_SIZE-2, &value32) == MMIO_ERROR_ARG);
  52. passert(mmio_read32(mmio, PAGE_SIZE-1, &value32) == MMIO_ERROR_ARG);
  53. passert(mmio_read32(mmio, PAGE_SIZE, &value32) == MMIO_ERROR_ARG);
  54. passert(mmio_close(mmio) == 0);
  55. /* Open unaligned base */
  56. address = CONTROL_MODULE_BASE + 123;
  57. passert(mmio_open(mmio, address, PAGE_SIZE) == 0);
  58. passert(mmio_base(mmio) == address);
  59. passert(mmio_size(mmio) == PAGE_SIZE);
  60. passert(mmio_ptr(mmio) != NULL);
  61. /* Check alignment math */
  62. passert(((struct mmio_handle *)mmio)->base == address);
  63. passert(((struct mmio_handle *)mmio)->size == PAGE_SIZE);
  64. passert(((struct mmio_handle *)mmio)->aligned_base == (address - (address % sysconf(_SC_PAGESIZE))));
  65. passert(((struct mmio_handle *)mmio)->aligned_size == (PAGE_SIZE + (address % sysconf(_SC_PAGESIZE))));
  66. passert((size_t)((uint8_t *)mmio_ptr(mmio) - (uint8_t *)((struct mmio_handle *)mmio)->ptr) ==
  67. (size_t)(((struct mmio_handle *)mmio)->base - ((struct mmio_handle *)mmio)->aligned_base));
  68. passert(mmio_read32(mmio, PAGE_SIZE-3, &value32) == MMIO_ERROR_ARG);
  69. passert(mmio_read32(mmio, PAGE_SIZE-2, &value32) == MMIO_ERROR_ARG);
  70. passert(mmio_read32(mmio, PAGE_SIZE-1, &value32) == MMIO_ERROR_ARG);
  71. passert(mmio_read32(mmio, PAGE_SIZE, &value32) == MMIO_ERROR_ARG);
  72. passert(mmio_close(mmio) == 0);
  73. /* Free MMIO */
  74. mmio_free(mmio);
  75. }
  76. void test_loopback(void) {
  77. mmio_t *mmio;
  78. uint32_t value32;
  79. uint8_t data[4];
  80. uint8_t vector[] = { 0xaa, 0xbb, 0xcc, 0xdd };
  81. ptest();
  82. /* Allocate MMIO */
  83. mmio = mmio_new();
  84. passert(mmio != NULL);
  85. /* Read USB VID/PID */
  86. passert(mmio_open(mmio, CONTROL_MODULE_BASE, PAGE_SIZE) == 0);
  87. passert(mmio_read32(mmio, USB_VID_PID_OFFSET, &value32) == 0);
  88. passert(value32 == USB_VID_PID);
  89. passert(mmio_close(mmio) == 0);
  90. /* Read USB VID/PID via byte read */
  91. passert(mmio_open(mmio, CONTROL_MODULE_BASE, PAGE_SIZE) == 0);
  92. passert(mmio_read(mmio, USB_VID_PID_OFFSET, data, 4) == 0);
  93. passert(data[0] == (USB_VID_PID & 0xff));
  94. passert(data[1] == ((USB_VID_PID >> 8) & 0xff));
  95. passert(data[2] == ((USB_VID_PID >> 16) & 0xff));
  96. passert(data[3] == ((USB_VID_PID >> 24) & 0xff));
  97. passert(mmio_close(mmio) == 0);
  98. /* Write/Read RTC Scratch2 Register */
  99. passert(mmio_open(mmio, RTCSS_BASE, PAGE_SIZE) == 0);
  100. passert(mmio_write32(mmio, RTC_SCRATCH2_REG_OFFSET, 0xdeadbeef) == 0);
  101. passert(mmio_read32(mmio, RTC_SCRATCH2_REG_OFFSET, &value32) == 0);
  102. passert(value32 == 0xdeadbeef);
  103. passert(mmio_close(mmio) == 0);
  104. /* Write/Read RTC Scratch2 Register via byte write */
  105. passert(mmio_open(mmio, RTCSS_BASE, PAGE_SIZE) == 0);
  106. passert(mmio_write(mmio, RTC_SCRATCH2_REG_OFFSET, vector, 4) == 0);
  107. passert(mmio_read32(mmio, RTC_SCRATCH2_REG_OFFSET, &value32) == 0);
  108. passert(value32 == 0xddccbbaa);
  109. passert(mmio_read(mmio, RTC_SCRATCH2_REG_OFFSET, data, 4) == 0);
  110. passert(memcmp(data, vector, 4) == 0);
  111. passert(mmio_close(mmio) == 0);
  112. /* Free MMIO */
  113. mmio_free(mmio);
  114. }
  115. struct rtc_ss {
  116. volatile uint32_t seconds; /* 0x00 */
  117. volatile uint32_t minutes; /* 0x04 */
  118. volatile uint32_t hours; /* 0x08 */
  119. volatile uint32_t days; /* 0x0C */
  120. volatile uint32_t months; /* 0x10 */
  121. volatile uint32_t years; /* 0x14 */
  122. volatile uint32_t weeks; /* 0x18 */
  123. volatile uint32_t reserved1; /* 0x1C */
  124. volatile uint32_t alarm_seconds; /* 0x20 */
  125. volatile uint32_t alarm_minutes; /* 0x24 */
  126. volatile uint32_t alarm_hours; /* 0x28 */
  127. volatile uint32_t alarm_days; /* 0x2C */
  128. volatile uint32_t alarm_months; /* 0x30 */
  129. volatile uint32_t alarm_years; /* 0x34 */
  130. volatile uint32_t reserved2; /* 0x38 */
  131. volatile uint32_t reserved3; /* 0x3C */
  132. volatile uint32_t rtc_ctrl; /* 0x40 */
  133. volatile uint32_t rtc_status; /* 0x44 */
  134. volatile uint32_t rtc_interrupts;/* 0x48 */
  135. };
  136. #define BCD_HI(x) (((x) >> 4) & 0xf)
  137. #define BCD_LO(x) ((x) & 0xf)
  138. #define BCD2DEC(x) (10*BCD_HI(x) + BCD_LO(x))
  139. void test_interactive(void) {
  140. mmio_t *mmio;
  141. uint32_t rtc_start, rtc_stop;
  142. time_t start, stop;
  143. struct rtc_ss *rtc;
  144. ptest();
  145. /* Allocate MMIO */
  146. mmio = mmio_new();
  147. passert(mmio != NULL);
  148. passert(mmio_open(mmio, RTCSS_BASE, PAGE_SIZE) == 0);
  149. rtc = (struct rtc_ss *)mmio_ptr(mmio);
  150. printf("Waiting for seconds ones digit to reset to 0...\n");
  151. start = time(NULL);
  152. /* Wait until seconds low go to 0, so we don't have to deal with overflows
  153. * in comparing times */
  154. while (BCD_LO(rtc->seconds) != 0) {
  155. usleep(500000);
  156. passert((time(NULL) - start) < 12);
  157. }
  158. start = time(NULL);
  159. rtc_start = rtc->seconds;
  160. printf("Date: %04d-%02d-%02d\n", 2000 + BCD2DEC(rtc->years), BCD2DEC(rtc->months), BCD2DEC(rtc->days));
  161. printf("Time: %02d:%02d:%02d %s\n", BCD2DEC(rtc->hours & 0x7f), BCD2DEC(rtc->minutes), BCD2DEC(rtc->seconds), (rtc->hours & 0x80) ? "PM" : "AM");
  162. sleep(3);
  163. printf("Date: %02d-%02d-%02d\n", 2000 + BCD2DEC(rtc->years), BCD2DEC(rtc->months), BCD2DEC(rtc->days));
  164. printf("Time: %02d:%02d:%02d %s\n", BCD2DEC(rtc->hours & 0x7f), BCD2DEC(rtc->minutes), BCD2DEC(rtc->seconds), (rtc->hours & 0x80) ? "PM" : "AM");
  165. rtc_stop = rtc->seconds;
  166. stop = time(NULL);
  167. /* Check that time has passed */
  168. passert((stop - start) > 2);
  169. passert((rtc_stop - rtc_start) > 2);
  170. passert(mmio_close(mmio) == 0);
  171. /* Free MMIO */
  172. mmio_free(mmio);
  173. }
  174. int main(void) {
  175. printf("WARNING: This test suite assumes a BeagleBone Black (AM335x) host!\n");
  176. printf("Other systems may experience unintended and dire consequences!\n");
  177. printf("Press enter to continue!\n");
  178. getc(stdin);
  179. test_arguments();
  180. printf(" " STR_OK " Arguments test passed.\n\n");
  181. test_open_config_close();
  182. printf(" " STR_OK " Open/close test passed.\n\n");
  183. test_loopback();
  184. printf(" " STR_OK " Loopback test passed.\n\n");
  185. test_interactive();
  186. printf(" " STR_OK " Interactive test passed.\n\n");
  187. printf("All tests passed!\n");
  188. return 0;
  189. }