nt9856x/BSP/linux-kernel/drivers/soc/nvt/otp/otp_proc.c
2023-03-28 15:07:53 +08:00

863 lines
26 KiB
C
Executable File

#include <linux/random.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include "otp_proc.h"
#include "otp_dbg.h"
#include "otp_main.h"
//#include "comm/timer.h"
#include "otp_platform.h"
//#include "kwrap/task.h"
#include <plat/hardware.h>
#include <plat/efuse_protected.h>
#include <mach/fmem.h>
#include <linux/scatterlist.h>
#include <crypto/skcipher.h>
//============================================================================
// Define
//============================================================================
#define MAX_CMD_LENGTH 30
#define MAX_ARG_NUM 6
#define DBG_TEST_EN (0)
//============================================================================
// Declaration
//============================================================================
typedef struct proc_cmd {
char cmd[MAX_CMD_LENGTH];
int (*execute)(PMODULE_INFO pdrv, unsigned char argc, char **argv);
} PROC_CMD, *PPROC_CMD;
//============================================================================
// Global variable
//============================================================================
POTP_DRV_INFO pdrv_otp_info_data;
//============================================================================
// Function define
//============================================================================
//=============================================================================
// proc "Custom Command" file operation functions
//=============================================================================
static int nvt_otp_proc_show(struct seq_file *sfile, void *v)
{
seq_printf(sfile, "\nUsage\n");
seq_printf(sfile, "\necho [command] > efuse_op\n\n");
seq_printf(sfile, "[command] =>\n");
seq_printf(sfile, " => trim (driver's trim data)\n");
seq_printf(sfile, " => uniqueid (chip's unique ID)\n");
seq_printf(sfile, " => keyset No (key transfer to secure engine)\n");
seq_printf(sfile, " => nvt_write_key No (write specific key into specific key set field)\n");
seq_printf(sfile, " => nvt_read_key No ( read specific key from specific key set field)\n");
seq_printf(sfile, " => nvt_read_key_lock No (Read lock specific key set)\n");
seq_printf(sfile, " => encrypt_key_set No (Encrypt/decrypt via specific key set)\n");
seq_printf(sfile, " => version (knlPkg.a version)\n");
return 0;
}
static int nvt_otp_proc_help_open(struct inode *inode, struct file *file)
{
return single_open(file, nvt_otp_proc_show, NULL);
}
static ssize_t nvt_otp_proc_cmd_read(struct file *fp, char __user *ubuf, size_t cnt, loff_t *ppos)
{
int ret = 0;
int len;
char kbuf[32];
UINT32 h, l;
// BOOL avl = FALSE;
//pr_info("nvt_check_available_proc_cmd_read cnt = [%d]\r\n", cnt);
if (!*ppos) {
// pr_info("Check linrary nane [%s]\r\n", library_name);
//avl = efuse_check_available(library_name);
h=0;
l=0;
if(efuse_get_unique_id(&l, &h) < 0) {
pr_err("unique ID[0x%08x][0x%08x] error\r\n", (int)h, (int)l);
h = 0;
l = 0;
sprintf(kbuf, "%08x%08x\n", h, l);
} else {
sprintf(kbuf, "%08x%08x\n", h, l);
}
len = strlen(kbuf);
if (clear_user((void *)ubuf, cnt)) {
printk(KERN_ERR "clear error\n");
return -EIO;
}
//ret = simple_read_from_buffer((char __user *)ubuf,cnt,ppos,kbuf,strlen(kbuf));
ret = copy_to_user(ubuf, kbuf, len);
// pr_info("efuse_unid %s ubuf %s len = %d\r\n", kbuf, ubuf, len);
*ppos += len;
return len;
}
return ret;
}
#if 0
//Crypto framework encrypt sample code start
struct tcrypt_result {
struct completion completion;
int err;
};
/* tie all data structures together */
struct skcipher_def {
struct scatterlist sg;
struct crypto_skcipher *tfm;
struct skcipher_request *req;
struct tcrypt_result result;
};
/* Callback function */
static void test_skcipher_cb(struct crypto_async_request *req, int error)
{
struct tcrypt_result *result = req->data;
if (error == -EINPROGRESS)
return;
result->err = error;
complete(&result->completion);
pr_info("Encryption finished successfully\n");
}
/* Perform cipher operation */
static unsigned int test_skcipher_encdec(struct skcipher_def *sk, int enc)
{
int rc = 0;
if (enc)
rc = crypto_skcipher_encrypt(sk->req);
else
rc = crypto_skcipher_decrypt(sk->req);
switch (rc) {
case 0:
break;
case -EINPROGRESS:
case -EBUSY:
rc = wait_for_completion_interruptible(
&sk->result.completion);
if (!rc && !sk->result.err) {
reinit_completion(&sk->result.completion);
break;
}
default:
pr_info("skcipher encrypt returned with %d result %d\n",
rc, sk->result.err);
break;
}
init_completion(&sk->result.completion);
return rc;
}
#endif
/******************************************************************
NA51068 efuse key section 640bit => 20 word
=============================================================
key# offset word[0] word[1] word[2] word[3]
=============================================================
key#0 [ 0] xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx => 128bit
key#1 [ 4] xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx => 128bit
key#2 [ 8] xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx => 128bit
key#3 [12] xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx => 128bit
key#4 [16] xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx => 128bit
*******************************************************************/
#define AES_ECB_KEY_SIZE 16
static UINT8 key_sample1[16] = {0x24, 0xaa, 0x0d, 0x9b, 0xf1, 0xae, 0x31, 0xb4, 0x28, 0x51, 0xe4, 0xc4, 0xd1, 0x71, 0x1d, 0x1e};
static UINT8 key_sample2[16] = {0x95, 0x4d, 0x81, 0xc5, 0x5a, 0xcc, 0x2b, 0xe5, 0xdd, 0xc8, 0x74, 0xc3, 0x9f, 0xaf, 0xcf, 0x5c};
static UINT8 key_sample3[16] = {0x04, 0x03, 0x02, 0x01, 0x08, 0x07, 0x06, 0x05, 0x12, 0x11, 0x10, 0x09, 0x16, 0x15, 0x14, 0x13};
//static UINT8 key_sample_crypto[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x9, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
//Here is specific key magic number to let linux crypto framework encrypt / decrypt via key manager
#define OTP_KEY_MANAGER_IDENTIFY_OFS 4
#define OTP_KEY_MANAGER_HDR_SIZE 8
const unsigned char OTP_KEY_MANAGER_HDR[OTP_KEY_MANAGER_HDR_SIZE]= {0x65, 0x6B, 0x65, 0x79, 0x00, 0x00, 0x00, 0x00}; ///< byte[0...3] as magic tag, byte[4] as key offset (word unit)
static ssize_t nvt_otp_proc_cmd_write(struct file *file, const char __user *buf, size_t size, loff_t *off)
{
int len = size;
char cmd_line[MAX_CMD_LENGTH];
char *cmdstr = cmd_line;
const char delimiters[] = {' ', 0x0A, 0x0D, '\0'};
char *argv[MAX_ARG_NUM] = {0};
unsigned char ucargc = 0;
// struct skcipher_def sk;
// struct crypto_skcipher *skcipher = NULL;
// struct skcipher_request *req = NULL;
// char *scratchpad = NULL;
// char *ivdata = NULL;
// unsigned char key[16];
// int ret = -EFAULT;
/*check command length*/
if ((!len) || (len > (MAX_CMD_LENGTH - 1))) {
pr_err("Command length is too long or 0!\n");
goto ERR_OUT;
}
/*copy command string from user space*/
if (copy_from_user(cmd_line, buf, len)) {
goto ERR_OUT;
}
cmd_line[len - 1] = '\0';
printk("CMD:%s\n", cmd_line);
/*parse command string*/
for (ucargc = 0; ucargc < MAX_ARG_NUM; ucargc++) {
argv[ucargc] = strsep(&cmdstr, delimiters);
if (argv[ucargc] == NULL) {
break;
}
}
if (ucargc < 1) {
pr_err("NULL command error\n");
goto ERR_OUT;
}
if (!strcmp(argv[0], "trim")) {
UINT16 data;
if (efuse_readParamOps(EFUSE_ETHERNET_TRIM_DATA, &data) != E_OK) {
pr_err("[0] data = NULL\n");
} else {
pr_info("[0] data = 0x%08x\r\n", data);
}
if (efuse_readParamOps(EFUSE_USBC_TRIM_DATA, &data) != E_OK) {
pr_err("[1] data = NULL\n");
} else {
pr_info("[1] data = 0x%08x\r\n", data);
}
if (efuse_readParamOps(EFUSE_DDRP_H_TRIM_DATA, &data) != E_OK) {
pr_err("[2] data = NULL\n");
} else {
pr_info("[2] data = 0x%08x\r\n", data);
}
if (efuse_readParamOps(EFUSE_VER_PKG_UID, &data) != E_OK) {
pr_err("[4] data = NULL\n");
} else {
pr_info("[4] data = 0x%08x\r\n", data);
}
#if defined(CONFIG_NVT_IVOT_PLAT_NA51055)
if (efuse_readParamOps(EFUSE_ADC_TRIM_A_DATA, &data) != E_OK) {
pr_err("[trim_A] data = NULL\n");
} else {
//Trim A @ bit[13..7]
data = ((data & 0x3F80)>>7);
pr_info("[trim_A] data = 0x%08x\r\n", data);
}
if (efuse_readParamOps(EFUSE_ADC_TRIM_B_DATA, &data) != E_OK) {
pr_err("[trim_A] data = NULL\n");
} else {
//Trim B @ bit[8..0]
data = (data & 0x1FF);
pr_info("[trim_B] data = 0x%08x\r\n", data);
}
#endif
#if defined(CONFIG_NVT_IVOT_PLAT_NA51089)
if (efuse_readParamOps(EFUSE_ADC_TRAM_A_DATA, &data) != E_OK) {
pr_err("[3] data = NULL\n");
} else {
pr_info("[3] data = 0x%08x\r\n", data);
}
if (efuse_readParamOps(EFUSE_DDRP_LDO_TRIM_DATA, &data) != E_OK) {
pr_err("[5] data = NULL\n");
} else {
pr_info("[5] data = 0x%08x\r\n", data);
}
#endif
if (efuse_readParamOps(EFUSE_THERMAL_TRIM_DATA, &data) != E_OK) {
pr_err("[6] data = NULL\n");
} else {
pr_info("[6] data = 0x%08x\r\n", data);
}
if (efuse_readParamOps(EFUSE_IDDQ_TRIM_DATA, &data) != E_OK) {
pr_err("[7] data = NULL\n");
} else {
pr_info("[7] data = 0x%08x\r\n", data);
}
#if defined(CONFIG_NVT_IVOT_PLAT_NA51089)
if (efuse_readParamOps(EFUSE_ADC_TRAM_B_DATA, &data) != E_OK) {
pr_err("[9] data = NULL\n");
} else {
pr_info("[9] data = 0x%08x\r\n", data);
}
#endif
//#endif
return size;
} else if(!strcmp(argv[0], "uniqueid")) {
UINT32 h, l;
h=0;
l=0;
if(efuse_get_unique_id(&l, &h) >= 0)
pr_info("unique ID[0x%08x][0x%08x] success\r\n", (int)h, (int)l);
else
pr_err("unique ID[0x%08x][0x%08x] error\r\n", (int)h, (int)l);
} else if(!strcmp(argv[0], "nvt_write_key")) {
UINT8 pKey[16];
INT32 result;
UINT32 key_set = EFUSE_OTP_1ST_KEY_SET_FIELD;
if(!strcmp(argv[1], "0")) {
key_set = EFUSE_OTP_1ST_KEY_SET_FIELD;
memcpy((void *)pKey, (void *)key_sample3, 16);
} else if(!strcmp(argv[1], "1")) {
key_set = EFUSE_OTP_2ND_KEY_SET_FIELD;
memcpy((void *)pKey, (void *)key_sample1, 16);
} else if(!strcmp(argv[1], "2")) {
key_set = EFUSE_OTP_3RD_KEY_SET_FIELD;
memcpy((void *)pKey, (void *)key_sample2, 16);
} else if(!strcmp(argv[1], "3")) {
key_set = EFUSE_OTP_4TH_KEY_SET_FIELD;
memcpy((void *)pKey, (void *)key_sample3, 16);
} else if(!strcmp(argv[1], "4")) {
key_set = EFUSE_OTP_5TH_KEY_SET_FIELD;
memcpy((void *)pKey, (void *)key_sample3, 16);
}
pr_info("nvt_write_key => [%s]", argv[1]);
result = otp_write_key(key_set, pKey);
if (result < 0) {
pr_info(" => fail [%d] \r\n", result);
return size;
} else {
pr_info(" => success\r\n");
}
} else if(!strcmp(argv[0], "nvt_read_key")) {
UINT8 pKey[16];
INT32 result;
UINT32 key_set = EFUSE_OTP_1ST_KEY_SET_FIELD;
if(!strcmp(argv[1], "0")) {
key_set = EFUSE_OTP_1ST_KEY_SET_FIELD;
} else if(!strcmp(argv[1], "1")) {
key_set = EFUSE_OTP_2ND_KEY_SET_FIELD;
} else if(!strcmp(argv[1], "2")) {
key_set = EFUSE_OTP_3RD_KEY_SET_FIELD;
} else if(!strcmp(argv[1], "3")) {
key_set = EFUSE_OTP_4TH_KEY_SET_FIELD;
} else if(!strcmp(argv[1], "4")) {
key_set = EFUSE_OTP_5TH_KEY_SET_FIELD;
}
pr_info("nvt_read_key => [%s]", argv[1]);
result = otp_read_key(key_set, pKey);
if (result < 0) {
pr_info(" => fail [%d] \r\n", result);
return size;
} else {
pr_info(" => success\r\n");
pr_info(" => value:%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\r\n",
pKey[0],pKey[1],pKey[2],pKey[3],
pKey[4],pKey[5],pKey[6],pKey[7],
pKey[8],pKey[9],pKey[10],pKey[11],
pKey[12],pKey[13],pKey[14],pKey[15]);
}
} else if(!strcmp(argv[0], "nvt_read_key_lock")) {
INT32 result;
UINT32 key_set = EFUSE_OTP_1ST_KEY_SET_FIELD;
if(!strcmp(argv[1], "0")) {
key_set = EFUSE_OTP_1ST_KEY_SET_FIELD;
} else if(!strcmp(argv[1], "1")) {
key_set = EFUSE_OTP_2ND_KEY_SET_FIELD;
} else if(!strcmp(argv[1], "2")) {
key_set = EFUSE_OTP_3RD_KEY_SET_FIELD;
} else if(!strcmp(argv[1], "3")) {
key_set = EFUSE_OTP_4TH_KEY_SET_FIELD;
} else if(!strcmp(argv[1], "4")) {
key_set = EFUSE_OTP_5TH_KEY_SET_FIELD;
}
pr_info("nvt_read_key_lock => [%s]", argv[1]);
result = otp_set_key_read_lock(key_set);
if (result < 0) {
pr_info(" => fail [%d] \r\n", result);
return size;
} else {
pr_info(" => success\r\n");
}
} else if(!strcmp(argv[0], "version")) {
#if defined(CONFIG_NVT_IVOT_PLAT_NA51089)
otp_version();
#else
pr_info("knlpkg.a 1.00.004\r\n");
#endif
} else if(!strcmp(argv[0], "jtag_disable")) {
if(is_JTAG_DISABLE_en() == TRUE)
pr_info("Disable JTAG success\r\n");
else
pr_info("Disable JTAG fail\r\n");
} else if(!strcmp(argv[0], "secure_enable")) {
if(otp_secure_en() == TRUE)
pr_info("Secure enable success\r\n");
else
pr_info("Secure enable fail\r\n");
} else if(!strcmp(argv[0], "data_area_encrypt")) {
if(otp_data_area_encrypt_en() == TRUE)
pr_info("Data area encrypt enable success\r\n");
else
pr_info("Data area encrypt enable fail\r\n");
} else if(!strcmp(argv[0], "signature_rsa_enable")) {
if(otp_signature_rsa_en() == TRUE)
pr_info("RSA signature enable success\r\n");
else
pr_info("RSA signature enable fail\r\n");
} else if(!strcmp(argv[0], "signature_rsa_chksum_enable")) {
if(otp_signature_rsa_chksum_en() == TRUE)
pr_info("RSA signature checksum enable success\r\n");
else
pr_info("RSA signature checksum enable fail\r\n");
} else if(!strcmp(argv[0], "trigger_key_set")) {
UINT32 key_set = EFUSE_OTP_1ST_KEY_SET_FIELD;
void __iomem *IOADDR_CRYPTO_REG_BASE;
if(!strcmp(argv[1], "0")) {
key_set = EFUSE_OTP_1ST_KEY_SET_FIELD;
} else if(!strcmp(argv[1], "1")) {
key_set = EFUSE_OTP_2ND_KEY_SET_FIELD;
} else if(!strcmp(argv[1], "2")) {
key_set = EFUSE_OTP_3RD_KEY_SET_FIELD;
} else if(!strcmp(argv[1], "3")) {
key_set = EFUSE_OTP_4TH_KEY_SET_FIELD;
} else if(!strcmp(argv[1], "4")) {
key_set = EFUSE_OTP_5TH_KEY_SET_FIELD;
}
pr_info("encrypt_key_set => @key [%s]", argv[1]);
trigger_efuse_key(EFUSE_KEY_MANAGER_CRYPTO, key_set * 4, 4);
if(!IOADDR_CRYPTO_REG_BASE) {
IOADDR_CRYPTO_REG_BASE = ioremap_nocache(0xF0620000, 0x100);
}
pr_info("0x10 0x%08x 0x%08x 0x%08x 0x%08x\r\n", nvt_readl(IOADDR_CRYPTO_REG_BASE+0x10), nvt_readl(IOADDR_CRYPTO_REG_BASE+0x14), nvt_readl(IOADDR_CRYPTO_REG_BASE+0x18), nvt_readl(IOADDR_CRYPTO_REG_BASE+0x1C));
pr_info("0x20 0x%08x 0x%08x 0x%08x 0x%08x\r\n", nvt_readl(IOADDR_CRYPTO_REG_BASE+0x20), nvt_readl(IOADDR_CRYPTO_REG_BASE+0x24), nvt_readl(IOADDR_CRYPTO_REG_BASE+0x28), nvt_readl(IOADDR_CRYPTO_REG_BASE+0x2C));
} else if(!strcmp(argv[0], "quary")) {
pr_info("=>[quary]\r\n");
pr_info(" is_secure_enable()=%d\r\n", is_secure_enable());
pr_info(" is_data_area_encrypted()=%d\r\n", is_data_area_encrypted());
pr_info(" is_signature_rsa()=%d\r\n", is_signature_rsa());
pr_info("is_signature_rsa_chsum_enable()=%d\r\n", is_signature_rsa_chsum_enable());
pr_info(" is_JTAG_DISABLE_en()=%d\r\n", is_JTAG_DISABLE_en());
pr_info(" is_1st_key_programmed()=%d\r\n", is_1st_key_programmed());
pr_info(" is_2nd_key_programmed()=%d\r\n", is_2nd_key_programmed());
pr_info(" is_3rd_key_programmed()=%d\r\n", is_3rd_key_programmed());
pr_info(" is_4th_key_programmed()=%d\r\n", is_4th_key_programmed());
pr_info(" is_5th_key_programmed()=%d\r\n", is_5th_key_programmed());
pr_info(" is_1st_key_read_lock()=%d\r\n", is_1st_key_read_lock());
pr_info(" is_2nd_key_read_lock()=%d\r\n", is_2nd_key_read_lock());
pr_info(" is_3rd_key_read_lock()=%d\r\n", is_3rd_key_read_lock());
pr_info(" is_4th_key_read_lock()=%d\r\n", is_4th_key_read_lock());
pr_info(" is_5th_key_read_lock()=%d\r\n", is_5th_key_read_lock());
#if defined(CONFIG_NVT_IVOT_PLAT_NA51089)
pr_info(" is_new_key_rule()=%d\r\n", is_new_key_rule());
#endif
}else {
pr_info("\nUsage\n");
pr_info("\necho [command] > otp_trim\n\n");
pr_info("[command] =>\n");
pr_info(" => trim\n");
pr_info(" => uniqueid (chip's unique ID)\n");
pr_info(" => nvt_write_key No (write specific key into specific key set field)\n");
pr_info(" => nvt_read_key No ( read specific key from specific key set field)\n");
pr_info(" => trigger_key_set No ( trigger key set field)\n");
pr_info(" => nvt_read_key_lock No (Read lock specific key set field => can not readable)\n");
pr_info(" => jtag_disable (Disable JTAG interface persistent)\n");
pr_info(" => secure_enable (ROM treat loader as secure enable)\n");
pr_info(" => data_area_encrypt(ROM treat loader data area as cypher text)\n");
pr_info(" => signature_rsa_enable(ROM treat loader by use RSA as loader's signature)o \n");
pr_info(" => signature_rsa_chksum_enable(Once use RSA as signature, enable RSA public checksum(use SHA256) enable)\n");
pr_info(" => quary(Query all option)\n");
pr_info(" => version (knlPkg.a version)\n");
}
ERR_OUT:
return size;
}
#if defined(CONFIG_NVT_IVOT_PLAT_NA51055) || defined(CONFIG_NVT_IVOT_PLAT_NA51089)
static void __iomem *IOADDR_TIMER_REG_BASE;
#define CALCULATE_CPU_FREQ_UNIT_US 5000
#define timer_gettick() readl(IOADDR_TIMER_REG_BASE + 0x108)
#define read_PMCR() \
({ \
unsigned long cfg; \
__asm__ __volatile__(\
"mrc p15, 0, %0, c9, c12, 0\n\t" \
: "=r"(cfg) \
);\
cfg;\
})
#define write_PMCR(m)\
({\
__asm__ __volatile__("mcr p15, 0, %0, c9, c12, 0" : : "r" (m));\
})
static BOOL cpu_count_open = FALSE;
static void ca53_cycle_count_start(BOOL do_reset, BOOL enable_divider)
{
/* in general enable all counters (including cycle counter)*/
int value = 1;
if (cpu_count_open == TRUE) {
pr_err("cpu count start already\r\n");
return;
}
cpu_count_open = TRUE;
if (do_reset) {
value |= 2; /* reset all counters to zero.*/
value |= 4; /* reset cycle counter to zero.*/
}
if (enable_divider) {
value |= 8; /* enable "by 64" divider for CCNT.*/
}
value |= 16;
/* program the performance-counter control-register: */
asm volatile("MCR p15, 0, %0, c9, c12, 0\t\n" :: "r"(value));
/* enable all counters: */
asm volatile("MCR p15, 0, %0, c9, c12, 1\t\n" :: "r"(0x8000000f));
/* clear overflows: */
asm volatile("MCR p15, 0, %0, c9, c12, 3\t\n" :: "r"(0x8000000f));
return;
}
/**
CA53 get CPU clock cycle count
get CPU clock cycle count
@param[out] type
@return success or not
- @b UINT64: clock cycle of CPU
*/
static u32 ca53_get_cycle_count(void)
{
unsigned int value;
__asm__ __volatile__("mrc p15, 0, %0, c9, c13, 0\n\t"
: "=r"(value)
);
return value;
}
static void ca53_cycle_count_stop(void)
{
u32 pmcr_reg;
if (cpu_count_open == FALSE) {
pr_err("cpu count not start yet\r\n");
return;
}
cpu_count_open = FALSE;
pmcr_reg = read_PMCR();
pmcr_reg &= ~(0x1 << 0); /*E*/
pmcr_reg &= ~(0x1 << 5); /*DP increase each clock cycle*/
write_PMCR(pmcr_reg);
return;
}
//static BOOL cpu_count_open = FALSE;
void timer2_delay(u32 us)
{
u32 start, end;
start = timer_gettick();
/*check timer count to target level*/
while (1) {
end = timer_gettick();
if ((end - start) > us) {
break;
}
}
}
static int do_nvt_cpu_get_freq(void)
{
u32 time_1, time_2, temp, time_interval;
u32 freq;
unsigned long spin_flags;
if (!IOADDR_TIMER_REG_BASE) {
IOADDR_TIMER_REG_BASE = ioremap_nocache(NVT_TIMER_BASE_PHYS, 0x200);
}
spin_flags = otp_platform_spin_lock();
ca53_cycle_count_start(TRUE, FALSE);
time_1 = ca53_get_cycle_count();
timer2_delay(CALCULATE_CPU_FREQ_UNIT_US);
time_2 = ca53_get_cycle_count();
if (time_2 > time_1) {
time_interval = (time_2 - time_1);
} else {
temp = 0xFFFFFFFF - time_1;
time_interval = temp + time_2;
}
freq = (time_interval) / (CALCULATE_CPU_FREQ_UNIT_US);
ca53_cycle_count_stop();
otp_platform_spin_unlock(spin_flags);
iounmap((volatile void __iomem *)IOADDR_TIMER_REG_BASE);
IOADDR_TIMER_REG_BASE = NULL;
#if defined (CONFIG_NVT_IVOT_PLAT_NA51055)
pr_info("CHIP[NA51055] => CPU Freq %d MHz\n", freq);
#elif defined (CONFIG_NVT_IVOT_PLAT_NA51089)
pr_info("CHIP[NA51089] => CPU Freq %d MHz\n", freq);
#endif
return 0;
}
#endif
static struct file_operations proc_otp_fops = {
.owner = THIS_MODULE,
.open = nvt_otp_proc_help_open,
.release = single_release,
.read = nvt_otp_proc_cmd_read,
.llseek = seq_lseek,
.write = nvt_otp_proc_cmd_write
};
static int nvt_avl_proc_show(struct seq_file *sfile, void *v)
{
seq_printf(sfile, "\nUsage\n");
seq_printf(sfile, "\necho [command] > avl\n\n");
seq_printf(sfile, "[command] =>\n");
seq_printf(sfile, " => showavl (show available list)\n");
seq_printf(sfile, " => version (knlPkg.a version)\n");
#if defined(CONFIG_NVT_IVOT_PLAT_NA51055) || defined(CONFIG_NVT_IVOT_PLAT_NA51089)
seq_printf(sfile, " => cpufreq\n");
#endif
return 0;
}
static int nvt_avl_proc_help_open(struct inode *inode, struct file *file)
{
return single_open(file, nvt_avl_proc_show, NULL);
}
static ssize_t nvt_avl_proc_cmd_write(struct file *file, const char __user *buf, size_t size, loff_t *off)
{
int len = size;
char cmd_line[MAX_CMD_LENGTH];
char *cmdstr = cmd_line;
const char delimiters[] = {' ', 0x0A, 0x0D, '\0'};
char *argv[MAX_ARG_NUM] = {0};
unsigned char ucargc = 0;
/*check command length*/
if ((!len) || (len > (MAX_CMD_LENGTH - 1))) {
pr_err("Command length is too long or 0!\n");
goto ERR_OUT;
}
/*copy command string from user space*/
if (copy_from_user(cmd_line, buf, len)) {
goto ERR_OUT;
}
cmd_line[len - 1] = '\0';
printk("CMD:%s\n", cmd_line);
/*parse command string*/
for (ucargc = 0; ucargc < MAX_ARG_NUM; ucargc++) {
argv[ucargc] = strsep(&cmdstr, delimiters);
if (argv[ucargc] == NULL) {
break;
}
}
if (ucargc < 1) {
pr_err("NULL command error\n");
goto ERR_OUT;
}
if (!strcmp(argv[0], "showavl")) {
cmd_efuse_show_avl();
return size;
} else if(!strcmp(argv[0], "version")) {
pr_info("knlpkg.a 1.00.007\r\n");
} else if (!strcmp(argv[0], "cpufreq")) {
#if defined(CONFIG_NVT_IVOT_PLAT_NA51055) || defined(CONFIG_NVT_IVOT_PLAT_NA51089)
do_nvt_cpu_get_freq();
#endif
}
ERR_OUT:
return size;
}
static struct file_operations proc_avl_fops = {
.owner = THIS_MODULE,
.open = nvt_avl_proc_help_open,
.release = single_release,
.read = seq_read,
.llseek = seq_lseek,
.write = nvt_avl_proc_cmd_write
};
int nvt_otp_proc_init(POTP_DRV_INFO pdrv_info)
{
int ret = 0;
struct proc_dir_entry *pmodule_root = NULL;
struct proc_dir_entry *pentry = NULL;
pmodule_root = proc_mkdir("nvt_otp_op", NULL);
if (pmodule_root == NULL) {
nvt_dbg(ERR, "failed to create Module root\n");
ret = -EINVAL;
goto remove_root;
}
pdrv_info->pproc_otp_root = pmodule_root;
pentry = proc_create("otp_trim", S_IRUGO | S_IXUGO, pmodule_root, &proc_otp_fops);
if (pentry == NULL) {
nvt_dbg(ERR, "failed to create proc otp!\n");
ret = -EINVAL;
goto remove_cmd;
}
pdrv_info->pproc_otp_entry = pentry;
pentry = proc_create("avl", S_IRUGO | S_IXUGO, pmodule_root, &proc_avl_fops);
if (pentry == NULL) {
nvt_dbg(ERR, "failed to create proc avl!\n");
ret = -EINVAL;
goto remove_cmd;
}
pdrv_info->pproc_avl_entry = pentry;
return ret;
#if 0
pentry = proc_create("dram2_info", S_IRUGO | S_IXUGO, pmodule_root, &proc_dram2_fops);
if (pentry == NULL) {
nvt_dbg(ERR, "failed to create proc dram2!\n");
ret = -EINVAL;
goto remove_dram2_proc;
}
pdrv_info->pproc_dram2_entry = pentry;
pentry = proc_create("dram1_heavyload", S_IRUGO | S_IXUGO, pmodule_root, &proc_dram_heavyload_fops);
if (pentry == NULL) {
nvt_dbg(ERR, "failed to create proc dram1!\n");
ret = -EINVAL;
goto remove_dram1_heavyload_proc;
}
pdrv_info->pproc_dram1_heavyload_entry = pentry;
pentry = proc_create("dram2_heavyload", S_IRUGO | S_IXUGO, pmodule_root, &proc_dram2_heavyload_fops);
if (pentry == NULL) {
nvt_dbg(ERR, "failed to create proc dram2!\n");
ret = -EINVAL;
goto remove_dram2_heavyload_proc;
}
pdrv_info->pproc_dram2_heavyload_entry = pentry;
nvt_ddr_proc_cfg.timer_id = TIMER_INVALID;
nvt_dram2_proc_cfg.timer_id = TIMER_INVALID;
OS_CONFIG_FLAG(nvt_ddr_proc_flag_id);
OS_CONFIG_FLAG(nvt_dram1_heavyload_flag_id);
OS_CONFIG_FLAG(nvt_dram2_heavyload_flag_id);
THREAD_CREATE(nvt_ddr_proc_tsk_id, dbgut_tsk, NULL, "nvt_ddr_proc_tsk");
THREAD_CREATE(nvt_dram1_heavyload_tsk_id, heavyload_tsk, NULL, "nvt_dram1_heavyload_tsk");
THREAD_CREATE(nvt_dram2_heavyload_tsk_id, heavyload_tsk2, NULL, "nvt_dram2_heavyload_tsk");
THREAD_RESUME(nvt_ddr_proc_tsk_id);
THREAD_RESUME(nvt_dram1_heavyload_tsk_id);
THREAD_RESUME(nvt_dram2_heavyload_tsk_id);
#if (DBG_TEST_EN == 1)
pentry = proc_create("cmd", S_IRUGO | S_IXUGO, pmodule_root, &proc_cmd_fops);
if (pentry == NULL) {
nvt_dbg(ERR, "failed to create proc cmd!\n");
ret = -EINVAL;
goto remove_cmd;
}
pdrv_info->pproc_cmd_entry = pentry;
#endif
return ret;
remove_dram2_heavyload_proc:
proc_remove(pdrv_info->pproc_dram2_heavyload_entry);
remove_dram1_heavyload_proc:
proc_remove(pdrv_info->pproc_dram1_heavyload_entry);
remove_dram2_proc:
proc_remove(pdrv_info->pproc_dram2_entry);
#endif
remove_cmd:
proc_remove(pdrv_info->pproc_otp_entry);
proc_remove(pdrv_info->pproc_avl_entry);
remove_root:
proc_remove(pdrv_info->pproc_otp_root);
return ret;
}
int nvt_otp_proc_remove(POTP_DRV_INFO pdrv_info)
{
#if 0
printk("%s: rm thread 0x%x\r\n", __func__, (UINT32)nvt_ddr_proc_tsk_id);
set_flg(nvt_ddr_proc_flag_id, FLGDBGUT_QUIT);
set_flg(nvt_dram1_heavyload_flag_id, FLGDBGUT_QUIT_HVY);
set_flg(nvt_dram2_heavyload_flag_id, FLGDBGUT_QUIT_HVY2);
THREAD_DESTROY(nvt_ddr_proc_tsk_id);
THREAD_DESTROY(nvt_dram1_heavyload_tsk_id);
THREAD_DESTROY(nvt_dram2_heavyload_tsk_id);
printk("%s: rm flag\r\n", __func__);
rel_flg(nvt_ddr_proc_flag_id);
rel_flg(nvt_dram1_heavyload_flag_id);
rel_flg(nvt_dram2_heavyload_flag_id);
printk("%s: rm proc\r\n", __func__);
proc_remove(pdrv_info->pproc_dram2_heavyload_entry);
proc_remove(pdrv_info->pproc_dram1_heavyload_entry);
proc_remove(pdrv_info->pproc_dram2_entry);
proc_remove(pdrv_info->pproc_dram1_entry);
proc_remove(pdrv_info->pproc_ddr_root);
#endif
return 0;
}