forked from vsergeev/lua-periphery
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_mmio.lua
207 lines (161 loc) · 8.07 KB
/
test_mmio.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
--
-- lua-periphery by vsergeev
-- https://github.com/vsergeev/lua-periphery
-- License: MIT
--
require('test')
local periphery = require('periphery')
local MMIO = periphery.MMIO
--------------------------------------------------------------------------------
local PAGE_SIZE = 4096
local CONTROL_MODULE_BASE = 0x44e10000
local USB_VID_PID_OFFSET = 0x7f4
local USB_VID_PID = 0x04516141
local RTCSS_BASE = 0x44e3e000
local RTC_SCRATCH2_REG_OFFSET = 0x68
--------------------------------------------------------------------------------
function test_arguments()
ptest()
-- Check offset out of bounds in test_open_config_close()
end
function test_open_config_close()
local mmio = nil
ptest()
-- Make sure module version exists
passert("module version", MMIO.version ~= nil)
-- Open aligned base
passert_periphery_success("open aligned", function () mmio = MMIO(CONTROL_MODULE_BASE, PAGE_SIZE) end)
-- Check properties
passert("property base", mmio.base == CONTROL_MODULE_BASE)
passert("property size", mmio.size == PAGE_SIZE)
io.write(string.format("mmio: %s\n", mmio:__tostring()))
-- Try to write to immutable properties
passert_periphery_error("write immutable", function () mmio.base = 1000 end, "MMIO_ERROR_ARG")
passert_periphery_error("write immutable", function () mmio.size = 1000 end, "MMIO_ERROR_ARG")
-- Open unaligned base
passert_periphery_success("open unaligned", function () mmio = MMIO(CONTROL_MODULE_BASE + 123, PAGE_SIZE) end)
passert("property base", mmio.base == CONTROL_MODULE_BASE + 123)
passert("property size", mmio.size == PAGE_SIZE)
-- Read out of bounds
passert_periphery_error("read 1 byte over", function () mmio:read32(PAGE_SIZE-3) end, "MMIO_ERROR_ARG")
passert_periphery_error("read 2 bytes over", function () mmio:read32(PAGE_SIZE-2) end, "MMIO_ERROR_ARG")
passert_periphery_error("read 3 bytes over", function () mmio:read32(PAGE_SIZE-1) end, "MMIO_ERROR_ARG")
passert_periphery_error("read 4 bytes over", function () mmio:read32(PAGE_SIZE) end, "MMIO_ERROR_ARG")
passert_periphery_success("close unaligned", function () mmio:close() end)
-- Open with table arguments
passert_periphery_success("open aligned", function () mmio = MMIO{base = CONTROL_MODULE_BASE, size = PAGE_SIZE} end)
passert("property base", mmio.base == CONTROL_MODULE_BASE)
passert("property size", mmio.size == PAGE_SIZE)
passert_periphery_success("close aligned", function () mmio:close() end)
end
function test_loopback()
local mmio = nil
local value32 = nil
local data = nil
-- Read USB VID/PID
passert_periphery_success("open control module", function () mmio = MMIO(CONTROL_MODULE_BASE, PAGE_SIZE) end)
passert_periphery_success("read USB VID/PID offset", function () value32 = mmio:read32(USB_VID_PID_OFFSET) end)
passert("compare USB VID/PID", value32 == USB_VID_PID)
passert_periphery_success("close control module", function () mmio:close() end)
-- Read USB VID/PID via byte read
passert_periphery_success("open control module", function () mmio = MMIO(CONTROL_MODULE_BASE, PAGE_SIZE) end)
passert_periphery_success("read USB VID/PID offset", function () data = mmio:read(USB_VID_PID_OFFSET, 4) end)
passert("byte table length is 4", #data == 4)
passert("compare byte 1", data[1] == bit32.band(USB_VID_PID, 0xff))
passert("compare byte 2", data[2] == bit32.band(bit32.rshift(USB_VID_PID, 8), 0xff))
passert("compare byte 3", data[3] == bit32.band(bit32.rshift(USB_VID_PID, 16), 0xff))
passert("compare byte 4", data[4] == bit32.band(bit32.rshift(USB_VID_PID, 24), 0xff))
passert_periphery_success("close control module", function () mmio:close() end)
-- Write/Read RTC Scratch2 register
passert_periphery_success("open RTCSS", function () mmio = MMIO(RTCSS_BASE, PAGE_SIZE) end)
passert_periphery_success("write SCRATCH2 reg", function () mmio:write32(RTC_SCRATCH2_REG_OFFSET, 0xdeadbeef) end)
passert_periphery_success("read SCRATCH2 reg", function () value32 = mmio:read32(RTC_SCRATCH2_REG_OFFSET) end)
passert("compare write and readback", value32 == 0xdeadbeef)
passert_periphery_success("close RTCSS", function () mmio:close() end)
-- Write/Read RTC Scratch2 register via byte write
passert_periphery_success("open RTCSS", function () mmio = MMIO(RTCSS_BASE, PAGE_SIZE) end)
data = { 0xaa, 0xbb, 0xcc, 0xdd }
passert_periphery_success("write SCRATCH2 reg", function () mmio:write(RTC_SCRATCH2_REG_OFFSET, data) end)
passert_periphery_success("read SCRATCH2 reg", function () data = mmio:read(RTC_SCRATCH2_REG_OFFSET, 4) end)
passert("compare byte 1", data[1] == 0xaa)
passert("compare byte 2", data[2] == 0xbb)
passert("compare byte 3", data[3] == 0xcc)
passert("compare byte 4", data[4] == 0xdd)
passert_periphery_success("close RTCSS", function () mmio:close() end)
end
--[[
struct rtc_ss {
volatile uint32_t seconds; /* 0x00 */
volatile uint32_t minutes; /* 0x04 */
volatile uint32_t hours; /* 0x08 */
volatile uint32_t days; /* 0x0C */
volatile uint32_t months; /* 0x10 */
volatile uint32_t years; /* 0x14 */
volatile uint32_t weeks; /* 0x18 */
volatile uint32_t reserved1; /* 0x1C */
volatile uint32_t alarm_seconds; /* 0x20 */
volatile uint32_t alarm_minutes; /* 0x24 */
volatile uint32_t alarm_hours; /* 0x28 */
volatile uint32_t alarm_days; /* 0x2C */
volatile uint32_t alarm_months; /* 0x30 */
volatile uint32_t alarm_years; /* 0x34 */
volatile uint32_t reserved2; /* 0x38 */
volatile uint32_t reserved3; /* 0x3C */
volatile uint32_t rtc_ctrl; /* 0x40 */
volatile uint32_t rtc_status; /* 0x44 */
volatile uint32_t rtc_interrupts; /* 0x48 */
};
--]]
function _bcd_hi(x)
return bit32.band(bit32.rshift(x, 4), 0xf)
end
function _bcd_lo(x)
return bit32.band(x, 0xf)
end
function _bcd2dec(x)
return 10*_bcd_hi(x) + _bcd_lo(x)
end
function test_interactive()
local mmio = nil
local tic = nil
local toc = nil
local rtc_tic = nil
local rtc_toc = nil
ptest()
-- Open real time clock subsystem
passert_periphery_success("open RTCSS", function () mmio = MMIO(RTCSS_BASE, PAGE_SIZE) end)
io.write("Waiting for seconds ones digit to reset to 0...\n")
tic = os.time()
-- Wait until seconds low go to 0, so we don't have to deal with overflows
-- in comparing times
while (_bcd_lo(mmio:read32(0x00)) ~= 0) do
periphery.sleep(1)
passert("less than 12 seconds elapsed", (os.time() - tic) < 12)
end
-- Compare passage of os time with rtc time
tic = os.time()
rtc_tic = _bcd_lo(mmio:read32(0x00))
io.write(string.format("Date: %04d-%02d-%02d\n", 2000 + _bcd2dec(mmio:read32(0x14)), _bcd2dec(mmio:read32(0x10)), _bcd2dec(mmio:read32(0x0c))))
io.write(string.format("Time: %02d:%02d:%02d\n", _bcd2dec(bit32.band(mmio:read32(0x08), 0x7f)), _bcd2dec(mmio:read32(0x04)), _bcd2dec(mmio:read32(0x00))))
periphery.sleep(3)
io.write(string.format("Date: %04d-%02d-%02d\n", 2000 + _bcd2dec(mmio:read32(0x14)), _bcd2dec(mmio:read32(0x10)), _bcd2dec(mmio:read32(0x0c))))
io.write(string.format("Time: %02d:%02d:%02d\n", _bcd2dec(bit32.band(mmio:read32(0x08), 0x7f)), _bcd2dec(mmio:read32(0x04)), _bcd2dec(mmio:read32(0x00))))
toc = os.time()
rtc_toc = _bcd_lo(mmio:read32(0x00))
passert("real time elapsed", (toc-tic) > 2)
passert("rtc time elapsed", (rtc_toc - rtc_tic) > 2)
passert_periphery_success("close RTCSS", function () mmio:close() end)
end
print("WARNING: This test suite assumes a BeagleBone Black (AM335x) host!")
print("Other systems may experience unintended and dire consequences!")
print("Press enter to continue!")
io.read()
test_arguments()
pokay("Arguments test passed.")
test_open_config_close()
pokay("Open/close test passed.")
test_loopback()
pokay("Loopback test passed.")
test_interactive()
pokay("Interactive test passed.")
pokay("All tests passed!")