1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <string.h>
9 #include <zephyr/cache.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/ztest.h>
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(test);
14
15 #include <mram_latency.h>
16
17 #define TIMEOUT_MS 10
18
19 static volatile uint32_t current_state;
20 static struct onoff_monitor monitor;
21 static struct onoff_client early_client;
22 static int early_rv;
23 static int early_result;
24
25 struct test_req {
26 struct onoff_client cli;
27 struct k_sem sem;
28 int res;
29 uint32_t state;
30 };
31
basic_cb(struct onoff_manager * mgr,struct onoff_client * cli,uint32_t state,int res)32 static void basic_cb(struct onoff_manager *mgr, struct onoff_client *cli, uint32_t state, int res)
33 {
34 struct test_req *req = CONTAINER_OF(cli, struct test_req, cli);
35
36 req->res = res;
37 req->state = state;
38 k_sem_give(&req->sem);
39 }
40
monitor_cb(struct onoff_manager * mgr,struct onoff_monitor * mon,uint32_t state,int res)41 static void monitor_cb(struct onoff_manager *mgr, struct onoff_monitor *mon, uint32_t state,
42 int res)
43 {
44 current_state = state;
45 }
46
ZTEST(mram_latency,test_basic_requests)47 ZTEST(mram_latency, test_basic_requests)
48 {
49 struct test_req req1, req2;
50 uint32_t exp_state;
51 int rv;
52
53 k_sem_init(&req1.sem, 0, 1);
54 k_sem_init(&req2.sem, 0, 1);
55
56 sys_notify_init_callback(&req1.cli.notify, basic_cb);
57 exp_state = ONOFF_STATE_OFF;
58 /* Req: 0->1 trigger to on */
59 rv = mram_no_latency_request(&req1.cli);
60 zassert_equal(rv, exp_state, "Unexpected rv:%d (exp:%d)", rv, exp_state);
61
62 sys_notify_init_callback(&req2.cli.notify, basic_cb);
63 exp_state = ONOFF_STATE_TO_ON;
64 /* Req: 1->2 */
65 rv = mram_no_latency_request(&req2.cli);
66 zassert_equal(rv, exp_state, "Unexpected rv:%d (exp:%d)", rv, exp_state);
67
68 rv = k_sem_take(&req1.sem, K_MSEC(TIMEOUT_MS));
69 zassert_equal(rv, 0, "Unexpected rv:%d", rv);
70 zassert_equal(req1.res, 0, "Unexpected res:%d", req1.res);
71 zassert_equal(req1.state, ONOFF_STATE_ON, "Unexpected state:%08x", req1.state);
72
73 rv = k_sem_take(&req2.sem, K_MSEC(TIMEOUT_MS));
74 zassert_equal(rv, 0, "Unexpected rv:%d", rv);
75 zassert_equal(req2.res, 0, "Unexpected res:%d", req2.res);
76 zassert_equal(req2.state, ONOFF_STATE_ON);
77
78 exp_state = ONOFF_STATE_ON;
79 rv = mram_no_latency_cancel_or_release(&req2.cli);
80 /* Req: 2->1 */
81 zassert_equal(rv, exp_state, "Unexpected rv:%d (exp:%d)", rv, exp_state);
82
83 /* Req: 1->0 going to off triggered*/
84 rv = mram_no_latency_cancel_or_release(&req1.cli);
85 zassert_equal(rv, exp_state, "Unexpected rv:%d (exp:%d)", rv, exp_state);
86
87 sys_notify_init_callback(&req1.cli.notify, basic_cb);
88 exp_state = ONOFF_STATE_OFF;
89
90 /* Req: 0->1 triggered to on while in to off. */
91 rv = mram_no_latency_request(&req1.cli);
92 zassert_equal(rv, exp_state, "Unexpected rv:%d (exp:%d)", rv, exp_state);
93
94 /* Req: 1->0 releases which to off. */
95 exp_state = ONOFF_STATE_TO_ON;
96 rv = mram_no_latency_cancel_or_release(&req1.cli);
97 zassert_equal(rv, exp_state, "Unexpected rv:%d (exp:%d)", rv, exp_state);
98
99 k_msleep(10);
100 }
101
timeout(struct k_timer * timer)102 static void timeout(struct k_timer *timer)
103 {
104 struct test_req *req = k_timer_user_data_get(timer);
105 uint32_t exp_state;
106 int rv;
107
108 sys_notify_init_callback(&req->cli.notify, basic_cb);
109 exp_state = ONOFF_STATE_OFF;
110 rv = mram_no_latency_request(&req->cli);
111 zassert_equal(rv, exp_state, "Unexpected rv:%d (exp:%d)", rv, exp_state);
112 }
113
ZTEST(mram_latency,test_req_from_irq)114 ZTEST(mram_latency, test_req_from_irq)
115 {
116 struct test_req req;
117 struct k_timer timer;
118 uint32_t exp_state;
119 int rv;
120
121 k_sem_init(&req.sem, 0, 1);
122 k_timer_init(&timer, timeout, NULL);
123 k_timer_user_data_set(&timer, &req);
124 /* Start k_timer and from that context request MRAM latency. */
125 k_timer_start(&timer, K_MSEC(1), K_NO_WAIT);
126
127 exp_state = ONOFF_STATE_ON;
128 rv = k_sem_take(&req.sem, K_MSEC(TIMEOUT_MS));
129 zassert_equal(rv, 0, "Unexpected rv:%d", rv);
130 zassert_equal(req.res, 0, "Unexpected res:%d", req.res);
131 zassert_equal(req.state, exp_state);
132
133 rv = mram_no_latency_cancel_or_release(&req.cli);
134 zassert_equal(rv, exp_state, "Unexpected rv:%d (exp:%d)", rv, exp_state);
135 }
136
ZTEST(mram_latency,test_sync_req)137 ZTEST(mram_latency, test_sync_req)
138 {
139 zassert_equal(current_state, ONOFF_STATE_OFF);
140 mram_no_latency_sync_request();
141 zassert_equal(current_state, ONOFF_STATE_ON);
142 mram_no_latency_sync_release();
143 zassert_equal(current_state, ONOFF_STATE_OFF);
144 }
145
ZTEST(mram_latency,test_early_req)146 ZTEST(mram_latency, test_early_req)
147 {
148 zassert_true(early_rv >= 0);
149 zassert_true(early_result >= 0);
150 }
151
setup(void)152 static void *setup(void)
153 {
154 int rv;
155
156 monitor.callback = monitor_cb;
157 rv = onoff_monitor_register(&mram_latency_mgr, &monitor);
158 zassert_equal(rv, 0);
159
160 if (early_rv >= 0) {
161 sys_notify_fetch_result(&early_client.notify, &early_result);
162 }
163
164 mram_no_latency_cancel_or_release(&early_client);
165
166 return NULL;
167 }
168
before(void * arg)169 static void before(void *arg)
170 {
171 zassert_equal(current_state, ONOFF_STATE_OFF);
172 }
173
after(void * arg)174 static void after(void *arg)
175 {
176 zassert_equal(current_state, ONOFF_STATE_OFF);
177 }
178
early_mram_client(void)179 static int early_mram_client(void)
180 {
181 sys_notify_init_spinwait(&early_client.notify);
182 early_rv = mram_no_latency_request(&early_client);
183
184 return 0;
185 }
186
187 SYS_INIT(early_mram_client, PRE_KERNEL_2, 0);
188
189 ZTEST_SUITE(mram_latency, NULL, setup, before, after, NULL);
190