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