Skip to content

Commit 7409ac9

Browse files
committed
samples: wifi: radio_test: Move FICR related file to radio test
Move ficr_prog.c from drivers to radio test sample as it is only used in the sample. Signed-off-by: Bansidhar P.M <[email protected]>
1 parent fa6b009 commit 7409ac9

File tree

4 files changed

+405
-1
lines changed

4 files changed

+405
-1
lines changed

samples/wifi/radio_test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ target_sources(app PRIVATE
1919
src/nrf_wifi_radio_test_main.c
2020
src/nrf_wifi_radio_test_shell.c
2121
src/nrf_wifi_radio_ficr_shell.c
22+
src/ficr_prog.c
2223
)

samples/wifi/radio_test/inc/nrf_wifi_radio_test_shell.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include <ctype.h>
1717
#include <host_rpu_sys_if.h>
1818
#include <fmac_structs.h>
19-
#include "rpu_hw_if.h"
19+
#include <zephyr/drivers/wifi/nrf_wifi/bus/rpu_hw_if.h>
2020

2121
struct nrf_wifi_ctx_zep_rt {
2222
struct nrf_wifi_fmac_priv *fmac_priv;
Lines changed: 380 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,380 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
/* @file
8+
* @brief NRF Wi-Fi radio FICR programming functions
9+
*/
10+
11+
#include <zephyr/logging/log.h>
12+
#include <zephyr/kernel.h>
13+
#include <zephyr/drivers/wifi/nrf_wifi/bus/rpu_hw_if.h>
14+
15+
#include "rpu_if.h"
16+
#include "ficr_prog.h"
17+
18+
19+
LOG_MODULE_DECLARE(otp_prog, CONFIG_WIFI_LOG_LEVEL);
20+
21+
static void write_word(unsigned int addr, unsigned int data)
22+
{
23+
rpu_write(addr, &data, 4);
24+
}
25+
26+
static void read_word(unsigned int addr, unsigned int *data)
27+
{
28+
rpu_read(addr, data, 4);
29+
}
30+
31+
unsigned int check_protection(unsigned int *buff, unsigned int off1, unsigned int off2,
32+
unsigned int off3, unsigned int off4)
33+
{
34+
if ((buff[off1] == OTP_PROGRAMMED) &&
35+
(buff[off2] == OTP_PROGRAMMED) &&
36+
(buff[off3] == OTP_PROGRAMMED) &&
37+
(buff[off4] == OTP_PROGRAMMED))
38+
return OTP_PROGRAMMED;
39+
else if ((buff[off1] == OTP_FRESH_FROM_FAB) &&
40+
(buff[off2] == OTP_FRESH_FROM_FAB) &&
41+
(buff[off3] == OTP_FRESH_FROM_FAB) &&
42+
(buff[off4] == OTP_FRESH_FROM_FAB))
43+
return OTP_FRESH_FROM_FAB;
44+
else if ((buff[off1] == OTP_ENABLE_PATTERN) &&
45+
(buff[off2] == OTP_ENABLE_PATTERN) &&
46+
(buff[off3] == OTP_ENABLE_PATTERN) &&
47+
(buff[off4] == OTP_ENABLE_PATTERN))
48+
return OTP_ENABLE_PATTERN;
49+
else
50+
return OTP_INVALID;
51+
}
52+
53+
54+
static void set_otp_timing_reg_40mhz(void)
55+
{
56+
write_word(OTP_TIMING_REG1_ADDR, OTP_TIMING_REG1_VAL);
57+
write_word(OTP_TIMING_REG2_ADDR, OTP_TIMING_REG2_VAL);
58+
}
59+
60+
static int poll_otp_ready(void)
61+
{
62+
int otp_mem_status = 0;
63+
int poll = 0;
64+
65+
while (poll != 100) {
66+
read_word(OTP_POLL_ADDR, &otp_mem_status);
67+
68+
if ((otp_mem_status & OTP_READY) == OTP_READY) {
69+
return 0;
70+
}
71+
poll++;
72+
}
73+
LOG_ERR("OTP is not ready");
74+
return -ENOEXEC;
75+
}
76+
77+
78+
static int req_otp_standby_mode(void)
79+
{
80+
write_word(OTP_RWSBMODE_ADDR, 0x0);
81+
return poll_otp_ready();
82+
}
83+
84+
85+
static int otp_wr_voltage_2V5(void)
86+
{
87+
int err;
88+
89+
err = req_otp_standby_mode();
90+
91+
if (err) {
92+
LOG_ERR("Failed Setting OTP voltage IOVDD to 2.5V");
93+
return -ENOEXEC;
94+
}
95+
write_word(OTP_VOLTCTRL_ADDR, OTP_VOLTCTRL_2V5);
96+
return 0;
97+
}
98+
99+
static int poll_otp_read_valid(void)
100+
{
101+
int otp_mem_status = 0;
102+
int poll = 0;
103+
104+
while (poll < 100) {
105+
read_word(OTP_POLL_ADDR, &otp_mem_status);
106+
107+
if ((otp_mem_status & OTP_READ_VALID) == OTP_READ_VALID) {
108+
return 0;
109+
}
110+
poll++;
111+
}
112+
LOG_ERR("%s: OTP read failed", __func__);
113+
return -ENOEXEC;
114+
}
115+
116+
static int poll_otp_wrdone(void)
117+
{
118+
int otp_mem_status = 0;
119+
int poll = 0;
120+
121+
while (poll < 100) {
122+
read_word(OTP_POLL_ADDR, &otp_mem_status);
123+
124+
if ((otp_mem_status & OTP_WR_DONE) == OTP_WR_DONE) {
125+
return 0;
126+
}
127+
poll++;
128+
}
129+
LOG_ERR("%s: OTP write done failed", __func__);
130+
return -ENOEXEC;
131+
}
132+
133+
static int req_otp_read_mode(void)
134+
{
135+
write_word(OTP_RWSBMODE_ADDR, OTP_READ_MODE);
136+
return poll_otp_ready();
137+
}
138+
139+
140+
static int req_otp_byte_write_mode(void)
141+
{
142+
write_word(OTP_RWSBMODE_ADDR, OTP_BYTE_WRITE_MODE);
143+
return poll_otp_ready();
144+
}
145+
146+
static unsigned int read_otp_location(unsigned int offset, unsigned int *read_val)
147+
{
148+
int err;
149+
150+
write_word(OTP_RDENABLE_ADDR, offset);
151+
err = poll_otp_read_valid();
152+
if (err) {
153+
LOG_ERR("OTP read failed");
154+
return err;
155+
}
156+
read_word(OTP_READREG_ADDR, read_val);
157+
158+
return 0;
159+
}
160+
161+
static int write_otp_location(unsigned int otp_location_offset, unsigned int otp_data)
162+
{
163+
write_word(OTP_WRENABLE_ADDR, otp_location_offset);
164+
write_word(OTP_WRITEREG_ADDR, otp_data);
165+
166+
return poll_otp_wrdone();
167+
}
168+
169+
170+
static int otp_rd_voltage_1V8(void)
171+
{
172+
int err;
173+
174+
err = req_otp_standby_mode();
175+
if (err) {
176+
LOG_ERR("error in %s", __func__);
177+
return err;
178+
}
179+
write_word(OTP_VOLTCTRL_ADDR, OTP_VOLTCTRL_1V8);
180+
181+
return 0;
182+
}
183+
184+
static int update_mac_addr(unsigned int index, unsigned int *write_val)
185+
{
186+
int ret = 0;
187+
188+
for (int i = 0; i < 2; i++) {
189+
ret = write_otp_location(MAC0_ADDR + 2 * index + i, write_val[i]);
190+
if (ret == -ENOEXEC) {
191+
LOG_ERR("FICR: Failed to update MAC ADDR%d", index);
192+
break;
193+
}
194+
LOG_INF("mac addr %d : Reg%d (0x%x) = 0x%04x",
195+
index, (i+1), (MAC0_ADDR + i) << 2, write_val[i]);
196+
}
197+
return ret;
198+
}
199+
200+
int write_otp_memory(unsigned int otp_addr, unsigned int *write_val)
201+
{
202+
int err = 0;
203+
int mask_val;
204+
int ret = 0;
205+
int retrim_loc = 0;
206+
207+
err = poll_otp_ready();
208+
if (err) {
209+
LOG_ERR("err in otp ready poll");
210+
return err;
211+
}
212+
213+
set_otp_timing_reg_40mhz();
214+
215+
err = otp_wr_voltage_2V5();
216+
if (err) {
217+
LOG_ERR("error in write_voltage 2V5");
218+
goto _exit_otp_write;
219+
}
220+
221+
err = req_otp_byte_write_mode();
222+
if (err) {
223+
LOG_ERR("error in OTP byte write mode");
224+
goto _exit_otp_write;
225+
}
226+
227+
switch (otp_addr) {
228+
case REGION_PROTECT:
229+
write_otp_location(REGION_PROTECT, write_val[0]);
230+
write_otp_location(REGION_PROTECT+1, write_val[0]);
231+
write_otp_location(REGION_PROTECT+2, write_val[0]);
232+
write_otp_location(REGION_PROTECT+3, write_val[0]);
233+
234+
LOG_INF("Written REGION_PROTECT0 (0x%x) : 0x%04x",
235+
(REGION_PROTECT << 2), write_val[0]);
236+
LOG_INF("Written REGION_PROTECT1 (0x%x) : 0x%04x",
237+
(REGION_PROTECT+1) << 2, write_val[0]);
238+
LOG_INF("Written REGION_PROTECT2 (0x%x) : 0x%04x",
239+
(REGION_PROTECT+2) << 2, write_val[0]);
240+
LOG_INF("Written REGION_PROTECT3 (0x%x) : 0x%04x",
241+
(REGION_PROTECT+3) << 2, write_val[0]);
242+
break;
243+
case QSPI_KEY:
244+
mask_val = QSPI_KEY_FLAG_MASK;
245+
for (int i = 0; i < QSPI_KEY_LENGTH_BYTES / 4; i++) {
246+
ret = write_otp_location(QSPI_KEY + i, write_val[i]);
247+
if (ret == -ENOEXEC) {
248+
LOG_ERR("FICR: Failed to write QSPI key offset-%d", QSPI_KEY + i);
249+
goto _exit_otp_write;
250+
}
251+
LOG_INF("Written QSPI_KEY0 (0x%x) : 0x%04x",
252+
(QSPI_KEY + i) << 2, write_val[i]);
253+
}
254+
write_otp_location(REGION_DEFAULTS, mask_val);
255+
LOG_INF("Written REGION_DEFAULTS (0x%x) : 0x%04x",
256+
(REGION_DEFAULTS) << 2, mask_val);
257+
break;
258+
case MAC0_ADDR:
259+
mask_val = MAC0_ADDR_FLAG_MASK;
260+
ret = update_mac_addr(0, write_val);
261+
if (ret == -ENOEXEC) {
262+
goto _exit_otp_write;
263+
}
264+
265+
write_otp_location(REGION_DEFAULTS, mask_val);
266+
LOG_INF("Written MAC address 0");
267+
LOG_INF("Written REGION_DEFAULTS (0x%x) : 0x%04x",
268+
(REGION_DEFAULTS) << 2, mask_val);
269+
break;
270+
case MAC1_ADDR:
271+
mask_val = MAC1_ADDR_FLAG_MASK;
272+
ret = update_mac_addr(1, write_val);
273+
if (ret == -ENOEXEC) {
274+
goto _exit_otp_write;
275+
}
276+
write_otp_location(REGION_DEFAULTS, mask_val);
277+
LOG_INF("Written MAC address 1");
278+
LOG_INF("Written REGION_DEFAULTS (0x%x) : 0x%04x",
279+
(REGION_DEFAULTS) << 2, mask_val);
280+
break;
281+
case CALIB_XO:
282+
mask_val = CALIB_XO_FLAG_MASK;
283+
ret = write_otp_location(CALIB_XO, write_val[0]);
284+
285+
if (ret == -ENOEXEC) {
286+
LOG_ERR("XO_Update Exception");
287+
goto _exit_otp_write;
288+
} else {
289+
write_otp_location(REGION_DEFAULTS, mask_val);
290+
291+
LOG_INF("Written CALIB_XO (0x%x) to 0x%04x",
292+
CALIB_XO << 2, write_val[0]);
293+
LOG_INF("Written REGION_DEFAULTS (0x%x) : 0x%04x",
294+
(REGION_DEFAULTS) << 2, mask_val);
295+
}
296+
break;
297+
case PRODRETEST_PROGVERSION:
298+
ret = write_otp_location(PRODRETEST_PROGVERSION, *write_val);
299+
300+
if (ret == -ENOEXEC) {
301+
LOG_ERR("PRODRETEST.PROGVERSION_Update Exception");
302+
goto _exit_otp_write;
303+
} else {
304+
LOG_INF("Written PRODRETEST.PROGVERSION 0x%04x", *write_val);
305+
}
306+
break;
307+
case PRODRETEST_TRIM0:
308+
case PRODRETEST_TRIM1:
309+
case PRODRETEST_TRIM2:
310+
case PRODRETEST_TRIM3:
311+
case PRODRETEST_TRIM4:
312+
case PRODRETEST_TRIM5:
313+
case PRODRETEST_TRIM6:
314+
case PRODRETEST_TRIM7:
315+
case PRODRETEST_TRIM8:
316+
case PRODRETEST_TRIM9:
317+
case PRODRETEST_TRIM10:
318+
case PRODRETEST_TRIM11:
319+
case PRODRETEST_TRIM12:
320+
case PRODRETEST_TRIM13:
321+
case PRODRETEST_TRIM14:
322+
retrim_loc = otp_addr - PRODRETEST_TRIM0;
323+
ret = write_otp_location(otp_addr, *write_val);
324+
325+
if (ret == -ENOEXEC) {
326+
LOG_ERR("PRODRETEST.TRIM_Update Exception");
327+
goto _exit_otp_write;
328+
} else {
329+
LOG_INF("Written PRODRETEST.TRIM%d 0x%04x",
330+
retrim_loc, *write_val);
331+
}
332+
break;
333+
case REGION_DEFAULTS:
334+
write_otp_location(REGION_DEFAULTS, write_val[0]);
335+
336+
LOG_INF("Written REGION_DEFAULTS (0x%x) to 0x%04x",
337+
REGION_DEFAULTS << 2, write_val[0]);
338+
break;
339+
default:
340+
LOG_ERR("unknown field received: %d", otp_addr);
341+
342+
}
343+
return ret;
344+
345+
_exit_otp_write:
346+
err = req_otp_standby_mode();
347+
err |= otp_rd_voltage_1V8();
348+
return err;
349+
}
350+
351+
int read_otp_memory(unsigned int otp_addr, unsigned int *read_val, int len)
352+
{
353+
int err;
354+
355+
err = poll_otp_ready();
356+
if (err) {
357+
LOG_ERR("err in otp ready poll");
358+
return -ENOEXEC;
359+
}
360+
361+
set_otp_timing_reg_40mhz();
362+
363+
err = otp_rd_voltage_1V8();
364+
if (err) {
365+
LOG_ERR("error in read_voltage 1V8");
366+
return -ENOEXEC;
367+
}
368+
369+
err = req_otp_read_mode();
370+
if (err) {
371+
LOG_ERR("error in req_otp_read_mode()");
372+
return -ENOEXEC;
373+
}
374+
375+
for (int i = 0; i < len; i++) {
376+
read_otp_location(otp_addr + i, &read_val[i]);
377+
}
378+
379+
return req_otp_standby_mode();
380+
}

0 commit comments

Comments
 (0)