863 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			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;
 | |
| }
 | 
