| 
 | 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 | + | 
 | 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 | + | 
 | 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 | + | 
 | 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 | + | 
 | 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 | + | 
 | 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 | + | 
 | 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 | + | 
 | 146 | +ZTEST(mram_latency, test_early_req)  | 
 | 147 | +{  | 
 | 148 | +	zassert_true(early_rv >= 0);  | 
 | 149 | +	zassert_true(early_result >= 0);  | 
 | 150 | +}  | 
 | 151 | + | 
 | 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 | + | 
 | 169 | +static void before(void *arg)  | 
 | 170 | +{  | 
 | 171 | +	zassert_equal(current_state, ONOFF_STATE_OFF);  | 
 | 172 | +}  | 
 | 173 | + | 
 | 174 | +static void after(void *arg)  | 
 | 175 | +{  | 
 | 176 | +	zassert_equal(current_state, ONOFF_STATE_OFF);  | 
 | 177 | +}  | 
 | 178 | + | 
 | 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);  | 
0 commit comments