Skip to content

Commit

Permalink
samples: wifi: radio_test: Move FICR related file to radio test
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
bama-nordic committed Dec 3, 2024
1 parent fa6b009 commit 7409ac9
Show file tree
Hide file tree
Showing 4 changed files with 405 additions and 1 deletion.
1 change: 1 addition & 0 deletions samples/wifi/radio_test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ target_sources(app PRIVATE
src/nrf_wifi_radio_test_main.c
src/nrf_wifi_radio_test_shell.c
src/nrf_wifi_radio_ficr_shell.c
src/ficr_prog.c
)
2 changes: 1 addition & 1 deletion samples/wifi/radio_test/inc/nrf_wifi_radio_test_shell.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include <ctype.h>
#include <host_rpu_sys_if.h>
#include <fmac_structs.h>
#include "rpu_hw_if.h"
#include <zephyr/drivers/wifi/nrf_wifi/bus/rpu_hw_if.h>

struct nrf_wifi_ctx_zep_rt {
struct nrf_wifi_fmac_priv *fmac_priv;
Expand Down
380 changes: 380 additions & 0 deletions samples/wifi/radio_test/src/ficr_prog.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,380 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

/* @file
* @brief NRF Wi-Fi radio FICR programming functions
*/

#include <zephyr/logging/log.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/wifi/nrf_wifi/bus/rpu_hw_if.h>

#include "rpu_if.h"
#include "ficr_prog.h"


LOG_MODULE_DECLARE(otp_prog, CONFIG_WIFI_LOG_LEVEL);

static void write_word(unsigned int addr, unsigned int data)
{
rpu_write(addr, &data, 4);
}

static void read_word(unsigned int addr, unsigned int *data)
{
rpu_read(addr, data, 4);
}

unsigned int check_protection(unsigned int *buff, unsigned int off1, unsigned int off2,
unsigned int off3, unsigned int off4)
{
if ((buff[off1] == OTP_PROGRAMMED) &&
(buff[off2] == OTP_PROGRAMMED) &&
(buff[off3] == OTP_PROGRAMMED) &&
(buff[off4] == OTP_PROGRAMMED))
return OTP_PROGRAMMED;
else if ((buff[off1] == OTP_FRESH_FROM_FAB) &&
(buff[off2] == OTP_FRESH_FROM_FAB) &&
(buff[off3] == OTP_FRESH_FROM_FAB) &&
(buff[off4] == OTP_FRESH_FROM_FAB))
return OTP_FRESH_FROM_FAB;
else if ((buff[off1] == OTP_ENABLE_PATTERN) &&
(buff[off2] == OTP_ENABLE_PATTERN) &&
(buff[off3] == OTP_ENABLE_PATTERN) &&
(buff[off4] == OTP_ENABLE_PATTERN))
return OTP_ENABLE_PATTERN;
else
return OTP_INVALID;
}


static void set_otp_timing_reg_40mhz(void)
{
write_word(OTP_TIMING_REG1_ADDR, OTP_TIMING_REG1_VAL);
write_word(OTP_TIMING_REG2_ADDR, OTP_TIMING_REG2_VAL);
}

static int poll_otp_ready(void)
{
int otp_mem_status = 0;
int poll = 0;

while (poll != 100) {
read_word(OTP_POLL_ADDR, &otp_mem_status);

if ((otp_mem_status & OTP_READY) == OTP_READY) {
return 0;
}
poll++;
}
LOG_ERR("OTP is not ready");
return -ENOEXEC;
}


static int req_otp_standby_mode(void)
{
write_word(OTP_RWSBMODE_ADDR, 0x0);
return poll_otp_ready();
}


static int otp_wr_voltage_2V5(void)
{
int err;

err = req_otp_standby_mode();

if (err) {
LOG_ERR("Failed Setting OTP voltage IOVDD to 2.5V");
return -ENOEXEC;
}
write_word(OTP_VOLTCTRL_ADDR, OTP_VOLTCTRL_2V5);
return 0;
}

static int poll_otp_read_valid(void)
{
int otp_mem_status = 0;
int poll = 0;

while (poll < 100) {
read_word(OTP_POLL_ADDR, &otp_mem_status);

if ((otp_mem_status & OTP_READ_VALID) == OTP_READ_VALID) {
return 0;
}
poll++;
}
LOG_ERR("%s: OTP read failed", __func__);
return -ENOEXEC;
}

static int poll_otp_wrdone(void)
{
int otp_mem_status = 0;
int poll = 0;

while (poll < 100) {
read_word(OTP_POLL_ADDR, &otp_mem_status);

if ((otp_mem_status & OTP_WR_DONE) == OTP_WR_DONE) {
return 0;
}
poll++;
}
LOG_ERR("%s: OTP write done failed", __func__);
return -ENOEXEC;
}

static int req_otp_read_mode(void)
{
write_word(OTP_RWSBMODE_ADDR, OTP_READ_MODE);
return poll_otp_ready();
}


static int req_otp_byte_write_mode(void)
{
write_word(OTP_RWSBMODE_ADDR, OTP_BYTE_WRITE_MODE);
return poll_otp_ready();
}

static unsigned int read_otp_location(unsigned int offset, unsigned int *read_val)
{
int err;

write_word(OTP_RDENABLE_ADDR, offset);
err = poll_otp_read_valid();
if (err) {
LOG_ERR("OTP read failed");
return err;
}
read_word(OTP_READREG_ADDR, read_val);

return 0;
}

static int write_otp_location(unsigned int otp_location_offset, unsigned int otp_data)
{
write_word(OTP_WRENABLE_ADDR, otp_location_offset);
write_word(OTP_WRITEREG_ADDR, otp_data);

return poll_otp_wrdone();
}


static int otp_rd_voltage_1V8(void)
{
int err;

err = req_otp_standby_mode();
if (err) {
LOG_ERR("error in %s", __func__);
return err;
}
write_word(OTP_VOLTCTRL_ADDR, OTP_VOLTCTRL_1V8);

return 0;
}

static int update_mac_addr(unsigned int index, unsigned int *write_val)
{
int ret = 0;

for (int i = 0; i < 2; i++) {
ret = write_otp_location(MAC0_ADDR + 2 * index + i, write_val[i]);
if (ret == -ENOEXEC) {
LOG_ERR("FICR: Failed to update MAC ADDR%d", index);
break;
}
LOG_INF("mac addr %d : Reg%d (0x%x) = 0x%04x",
index, (i+1), (MAC0_ADDR + i) << 2, write_val[i]);
}
return ret;
}

int write_otp_memory(unsigned int otp_addr, unsigned int *write_val)
{
int err = 0;
int mask_val;
int ret = 0;
int retrim_loc = 0;

err = poll_otp_ready();
if (err) {
LOG_ERR("err in otp ready poll");
return err;
}

set_otp_timing_reg_40mhz();

err = otp_wr_voltage_2V5();
if (err) {
LOG_ERR("error in write_voltage 2V5");
goto _exit_otp_write;
}

err = req_otp_byte_write_mode();
if (err) {
LOG_ERR("error in OTP byte write mode");
goto _exit_otp_write;
}

switch (otp_addr) {
case REGION_PROTECT:
write_otp_location(REGION_PROTECT, write_val[0]);
write_otp_location(REGION_PROTECT+1, write_val[0]);
write_otp_location(REGION_PROTECT+2, write_val[0]);
write_otp_location(REGION_PROTECT+3, write_val[0]);

LOG_INF("Written REGION_PROTECT0 (0x%x) : 0x%04x",
(REGION_PROTECT << 2), write_val[0]);
LOG_INF("Written REGION_PROTECT1 (0x%x) : 0x%04x",
(REGION_PROTECT+1) << 2, write_val[0]);
LOG_INF("Written REGION_PROTECT2 (0x%x) : 0x%04x",
(REGION_PROTECT+2) << 2, write_val[0]);
LOG_INF("Written REGION_PROTECT3 (0x%x) : 0x%04x",
(REGION_PROTECT+3) << 2, write_val[0]);
break;
case QSPI_KEY:
mask_val = QSPI_KEY_FLAG_MASK;
for (int i = 0; i < QSPI_KEY_LENGTH_BYTES / 4; i++) {
ret = write_otp_location(QSPI_KEY + i, write_val[i]);
if (ret == -ENOEXEC) {
LOG_ERR("FICR: Failed to write QSPI key offset-%d", QSPI_KEY + i);
goto _exit_otp_write;
}
LOG_INF("Written QSPI_KEY0 (0x%x) : 0x%04x",
(QSPI_KEY + i) << 2, write_val[i]);
}
write_otp_location(REGION_DEFAULTS, mask_val);
LOG_INF("Written REGION_DEFAULTS (0x%x) : 0x%04x",
(REGION_DEFAULTS) << 2, mask_val);
break;
case MAC0_ADDR:
mask_val = MAC0_ADDR_FLAG_MASK;
ret = update_mac_addr(0, write_val);
if (ret == -ENOEXEC) {
goto _exit_otp_write;
}

write_otp_location(REGION_DEFAULTS, mask_val);
LOG_INF("Written MAC address 0");
LOG_INF("Written REGION_DEFAULTS (0x%x) : 0x%04x",
(REGION_DEFAULTS) << 2, mask_val);
break;
case MAC1_ADDR:
mask_val = MAC1_ADDR_FLAG_MASK;
ret = update_mac_addr(1, write_val);
if (ret == -ENOEXEC) {
goto _exit_otp_write;
}
write_otp_location(REGION_DEFAULTS, mask_val);
LOG_INF("Written MAC address 1");
LOG_INF("Written REGION_DEFAULTS (0x%x) : 0x%04x",
(REGION_DEFAULTS) << 2, mask_val);
break;
case CALIB_XO:
mask_val = CALIB_XO_FLAG_MASK;
ret = write_otp_location(CALIB_XO, write_val[0]);

if (ret == -ENOEXEC) {
LOG_ERR("XO_Update Exception");
goto _exit_otp_write;
} else {
write_otp_location(REGION_DEFAULTS, mask_val);

LOG_INF("Written CALIB_XO (0x%x) to 0x%04x",
CALIB_XO << 2, write_val[0]);
LOG_INF("Written REGION_DEFAULTS (0x%x) : 0x%04x",
(REGION_DEFAULTS) << 2, mask_val);
}
break;
case PRODRETEST_PROGVERSION:
ret = write_otp_location(PRODRETEST_PROGVERSION, *write_val);

if (ret == -ENOEXEC) {
LOG_ERR("PRODRETEST.PROGVERSION_Update Exception");
goto _exit_otp_write;
} else {
LOG_INF("Written PRODRETEST.PROGVERSION 0x%04x", *write_val);
}
break;
case PRODRETEST_TRIM0:
case PRODRETEST_TRIM1:
case PRODRETEST_TRIM2:
case PRODRETEST_TRIM3:
case PRODRETEST_TRIM4:
case PRODRETEST_TRIM5:
case PRODRETEST_TRIM6:
case PRODRETEST_TRIM7:
case PRODRETEST_TRIM8:
case PRODRETEST_TRIM9:
case PRODRETEST_TRIM10:
case PRODRETEST_TRIM11:
case PRODRETEST_TRIM12:
case PRODRETEST_TRIM13:
case PRODRETEST_TRIM14:
retrim_loc = otp_addr - PRODRETEST_TRIM0;
ret = write_otp_location(otp_addr, *write_val);

if (ret == -ENOEXEC) {
LOG_ERR("PRODRETEST.TRIM_Update Exception");
goto _exit_otp_write;
} else {
LOG_INF("Written PRODRETEST.TRIM%d 0x%04x",
retrim_loc, *write_val);
}
break;
case REGION_DEFAULTS:
write_otp_location(REGION_DEFAULTS, write_val[0]);

LOG_INF("Written REGION_DEFAULTS (0x%x) to 0x%04x",
REGION_DEFAULTS << 2, write_val[0]);
break;
default:
LOG_ERR("unknown field received: %d", otp_addr);

}
return ret;

_exit_otp_write:
err = req_otp_standby_mode();
err |= otp_rd_voltage_1V8();
return err;
}

int read_otp_memory(unsigned int otp_addr, unsigned int *read_val, int len)
{
int err;

err = poll_otp_ready();
if (err) {
LOG_ERR("err in otp ready poll");
return -ENOEXEC;
}

set_otp_timing_reg_40mhz();

err = otp_rd_voltage_1V8();
if (err) {
LOG_ERR("error in read_voltage 1V8");
return -ENOEXEC;
}

err = req_otp_read_mode();
if (err) {
LOG_ERR("error in req_otp_read_mode()");
return -ENOEXEC;
}

for (int i = 0; i < len; i++) {
read_otp_location(otp_addr + i, &read_val[i]);
}

return req_otp_standby_mode();
}
Loading

0 comments on commit 7409ac9

Please sign in to comment.