[WCNCR00148023] misc: support efuse read/write/dump by shell command
[Description]
Add efuse read/write/dump by shell command
Support efuse read/write by iwpriv and efuse dump by procfs
rea/write command format:
Help menu
Read: "efuse read addr_hex"
Write: "efuse write addr_hex val_hex"
Command samples:
read (iwpriv)
iwpriv wlan0 driver "efuse read 0x0"
write (iwpriv)
iwpriv wlan0 driver "efuse write 0x0 0x68"
dump (procfs)
cat /proc/net/wlan/efuse_dump > /tmp/efuse_dump.txt
Feature: misc
Change-Id: I5b635984755b985ae5c3794251bfed2f7a5d7102
CR-Id: WCNCR00148023
Signed-off-by: Deren Wu <deren.wu@mediatek.com>
diff --git a/include/wlan_oid.h b/include/wlan_oid.h
index f83f843..0f77fd9 100644
--- a/include/wlan_oid.h
+++ b/include/wlan_oid.h
@@ -141,6 +141,7 @@
#define BT_PROFILE_PARAM_LEN 8
+#define EFUSE_ADDR_MAX 0x3BF /* Based on EEPROM layout 20160120 */
#if CFG_SUPPORT_BUFFER_MODE
/* For MT7668 */
diff --git a/os/linux/gl_proc.c b/os/linux/gl_proc.c
index 177b297..3fcfab0 100644
--- a/os/linux/gl_proc.c
+++ b/os/linux/gl_proc.c
@@ -69,6 +69,7 @@
* E X T E R N A L R E F E R E N C E S
********************************************************************************
*/
+#include "precomp.h"
#include "gl_os.h"
#include "gl_kal.h"
#include "debug.h"
@@ -93,6 +94,7 @@
#define PROC_DBG_LEVEL_NAME "dbg_level"
#define PROC_DRIVER_CMD "driver"
#define PROC_CFG "cfg"
+#define PROC_EFUSE_DUMP "efuse_dump"
@@ -183,6 +185,76 @@
#if WLAN_INCLUDE_PROC
#if CFG_SUPPORT_EASY_DEBUG
+static void *procEfuseDump_start(struct seq_file *s, loff_t *pos)
+{
+ static unsigned long counter;
+
+ if (*pos == 0)
+ counter = *pos; /* read file init */
+
+ if (counter >= EFUSE_ADDR_MAX)
+ return NULL;
+ return &counter;
+}
+static void *procEfuseDump_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ unsigned long *tmp_v = (unsigned long *)v;
+
+ (*tmp_v) += EFUSE_BLOCK_SIZE;
+
+ if (*tmp_v >= EFUSE_ADDR_MAX)
+ return NULL;
+ return tmp_v;
+}
+static void procEfuseDump_stop(struct seq_file *s, void *v)
+{
+ /* nothing to do, we use a static value in start() */
+}
+static int procEfuseDump_show(struct seq_file *s, void *v)
+{
+ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
+ UINT_32 u4BufLen = 0;
+ P_GLUE_INFO_T prGlueInfo;
+ UINT_32 idx_addr, idx_value;
+ PARAM_CUSTOM_ACCESS_EFUSE_T rAccessEfuseInfo = {};
+
+ prGlueInfo = g_prGlueInfo_proc;
+
+#if (CFG_EEPROM_PAGE_ACCESS == 1)
+ idx_addr = *(loff_t *)v;
+ rAccessEfuseInfo.u4Address = (idx_addr / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE;
+
+ rStatus = kalIoctl(prGlueInfo,
+ wlanoidQueryProcessAccessEfuseRead,
+ &rAccessEfuseInfo,
+ sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), TRUE, TRUE, TRUE, &u4BufLen);
+ if (rStatus != WLAN_STATUS_SUCCESS) {
+ seq_printf(s, "efuse read fail (0x%03X)\n", rAccessEfuseInfo.u4Address);
+ return 0;
+ }
+
+ for (idx_value = 0; idx_value < EFUSE_BLOCK_SIZE; idx_value++)
+ seq_printf(s, "0x%03X=0x%02X\n"
+ , rAccessEfuseInfo.u4Address+idx_value
+ , prGlueInfo->prAdapter->aucEepromVaule[idx_value]);
+ return 0;
+#else
+ seq_puts(s, "efuse ops is invalid\n");
+ return -EPERM; /* return negative value to stop read process */
+#endif
+}
+static int procEfuseDumpOpen(struct inode *inode, struct file *file)
+{
+ static const struct seq_operations procEfuseDump_ops = {
+ .start = procEfuseDump_start,
+ .next = procEfuseDump_next,
+ .stop = procEfuseDump_stop,
+ .show = procEfuseDump_show
+ };
+
+ return seq_open(file, &procEfuseDump_ops);
+}
+
static ssize_t procCfgRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
@@ -425,6 +497,14 @@
#if WLAN_INCLUDE_PROC
#if CFG_SUPPORT_EASY_DEBUG
+static const struct file_operations efusedump_ops = {
+ .owner = THIS_MODULE,
+ .open = procEfuseDumpOpen,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static const struct file_operations drivercmd_ops = {
.owner = THIS_MODULE,
.read = procDriverCmdRead,
@@ -741,6 +821,7 @@
remove_proc_entry(PROC_DRIVER_CMD, gprProcRoot);
remove_proc_entry(PROC_DBG_LEVEL_NAME, gprProcRoot);
remove_proc_entry(PROC_CFG, gprProcRoot);
+ remove_proc_entry(PROC_EFUSE_DUMP, gprProcRoot);
#if CFG_SUPPORT_DEBUG_FS
remove_proc_entry(PROC_ROAM_PARAM, gprProcRoot);
@@ -787,6 +868,12 @@
pr_err("Unable to create /proc entry for driver command\n\r");
return -1;
}
+
+ prEntry = proc_create(PROC_EFUSE_DUMP, 0664, gprProcRoot, &efusedump_ops);
+ if (prEntry == NULL) {
+ pr_err("Unable to create /proc entry efuse\n\r");
+ return -1;
+ }
#endif
prEntry = proc_create(PROC_DBG_LEVEL_NAME, 0664, gprProcRoot, &dbglevel_ops);
diff --git a/os/linux/gl_wext_priv.c b/os/linux/gl_wext_priv.c
index 96bae3c..48f8482 100644
--- a/os/linux/gl_wext_priv.c
+++ b/os/linux/gl_wext_priv.c
@@ -2247,6 +2247,8 @@
#define CMD_GET_CH_RANK_LIST "GET_CH_RANK_LIST"
#endif
+#define CMD_EFUSE "EFUSE"
+
/* miracast related definition */
#define MIRACAST_MODE_OFF 0
#define MIRACAST_MODE_SOURCE 1
@@ -7852,6 +7854,112 @@
}
#endif
+static int priv_driver_efuse_ops(IN struct net_device *prNetDev, IN char *pcCommand, IN int i4TotalLen)
+{
+ enum EFUSE_OP_MODE {
+ EFUSE_READ,
+ EFUSE_WRITE,
+ EFUSE_INVALID,
+ };
+ UINT_8 ucOpMode = EFUSE_INVALID;
+ UCHAR ucOpChar;
+ INT_32 i4Argc = 0;
+ PCHAR apcArgv[WLAN_CFG_ARGV_MAX];
+ UINT_32 u4Ret;
+ INT_32 i4Parameter;
+ UINT_32 u4Efuse_addr = 0;
+ UINT_8 ucEfuse_value = 0;
+
+#if (CFG_EEPROM_PAGE_ACCESS == 1)
+ WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
+ UINT_32 u4Offset = 0;
+ UINT_32 u4BufLen = 0;
+ UINT_8 u4Index = 0;
+ P_GLUE_INFO_T prGlueInfo = NULL;
+ PARAM_CUSTOM_ACCESS_EFUSE_T rAccessEfuseInfo;
+#endif
+ wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv);
+
+ /* Sanity check */
+ if (i4Argc < 2)
+ goto efuse_op_invalid;
+
+ ucOpChar = (UCHAR)apcArgv[1][0];
+ if ((i4Argc == 3) && (ucOpChar == 'r' || ucOpChar == 'R'))
+ ucOpMode = EFUSE_READ;
+ else if ((i4Argc == 4) && (ucOpChar == 'w' || ucOpChar == 'W'))
+ ucOpMode = EFUSE_WRITE;
+
+ /* Print out help if input format is wrong */
+ if (ucOpMode == EFUSE_INVALID)
+ goto efuse_op_invalid;
+
+ /* convert address */
+ if (ucOpMode == EFUSE_READ || ucOpMode == EFUSE_WRITE) {
+ u4Ret = kalkStrtos32(apcArgv[2], 16, &i4Parameter);
+ u4Efuse_addr = (UINT_32)i4Parameter;
+ }
+
+ /* convert value */
+ if (ucOpMode == EFUSE_WRITE) {
+ u4Ret = kalkStrtos32(apcArgv[3], 16, &i4Parameter);
+ ucEfuse_value = (UINT_8)i4Parameter;
+ }
+
+ /* Start operation */
+#if (CFG_EEPROM_PAGE_ACCESS == 1)
+ prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
+ kalMemSet(&rAccessEfuseInfo, 0, sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T));
+ rAccessEfuseInfo.u4Address = (u4Efuse_addr / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE;
+ u4Index = u4Efuse_addr % EFUSE_BLOCK_SIZE;
+
+ if (ucOpMode == EFUSE_READ) {
+ rStatus = kalIoctl(prGlueInfo,
+ wlanoidQueryProcessAccessEfuseRead,
+ &rAccessEfuseInfo,
+ sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), TRUE, TRUE, TRUE, &u4BufLen);
+
+ if (rStatus == WLAN_STATUS_SUCCESS) {
+ u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset,
+ "Read success 0x%X = 0x%X\n", u4Efuse_addr
+ , prGlueInfo->prAdapter->aucEepromVaule[u4Index]);
+ }
+ } else if (ucOpMode == EFUSE_WRITE) {
+
+ prGlueInfo->prAdapter->aucEepromVaule[u4Index] = ucEfuse_value;
+
+ kalMemCopy(rAccessEfuseInfo.aucData, prGlueInfo->prAdapter->aucEepromVaule, 16);
+
+ rStatus = kalIoctl(prGlueInfo,
+ wlanoidQueryProcessAccessEfuseWrite,
+ &rAccessEfuseInfo,
+ sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), FALSE, FALSE, TRUE, &u4BufLen);
+ if (rStatus == WLAN_STATUS_SUCCESS) {
+ u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset,
+ "Write success 0x%X = 0x%X\n"
+ , u4Efuse_addr
+ , ucEfuse_value);
+ }
+ }
+#else
+ u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset,
+ "efuse ops is invalid\n");
+#endif
+
+ return (INT_32)u4Offset;
+
+efuse_op_invalid:
+
+ u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset,
+ "\nHelp menu\n");
+ u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset,
+ "\tRead:\t\"efuse read addr_hex\"\n");
+ u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset,
+ "\tWrite:\t\"efuse write addr_hex val_hex\"\n");
+ return (INT_32)u4Offset;
+}
+
+
INT_32 priv_driver_cmds(IN struct net_device *prNetDev, IN PCHAR pcCommand, IN INT_32 i4TotalLen)
{
P_GLUE_INFO_T prGlueInfo = NULL;
@@ -8065,6 +8173,8 @@
else if (strnicmp(pcCommand, CMD_GET_CH_RANK_LIST, strlen(CMD_GET_CH_RANK_LIST)) == 0)
i4BytesWritten = priv_driver_get_ch_rank_list(prNetDev, pcCommand, i4TotalLen);
#endif
+ else if (strnicmp(pcCommand, CMD_EFUSE, sizeof(CMD_EFUSE)-1) == 0)
+ i4BytesWritten = priv_driver_efuse_ops(prNetDev, pcCommand, i4TotalLen);
else
i4CmdFound = 0;
}