| /* drivers/mtd/mtdadapt.c  | 
 | *  | 
 | * Mtd api adapt driver for nand&nor.  | 
 | *  | 
 | * Copyright (c) 2018 ZTE Ltd.  | 
 | *  | 
 | * This software is licensed under the terms of the GNU General Public  | 
 | * License version 2, as published by the Free Software Foundation, and  | 
 | * may be copied, distributed, and modified under those terms.  | 
 | *  | 
 | * This program is distributed in the hope that it will be useful,  | 
 | * but WITHOUT ANY WARRANTY; without even the implied warranty of  | 
 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  | 
 | * GNU General Public License for more details.  | 
 | *  | 
 | */  | 
 |  | 
 | #include <linux/slab.h>  | 
 | #include <linux/kernel.h>  | 
 | #include <linux/mtd/mtd.h> | 
 | #include <linux/module.h> | 
 | #include <linux/soc/zte/otp/otp_zx.h> | 
 |  | 
 | #define READ_ZLOADER_FLAG_SIZE 0x800 | 
 | #define WRITE_ZLOADER_FLAG_SIZE 0x3000 | 
 |  | 
 |  | 
 | extern struct mtd_info *mtd_fota; | 
 | extern int g_zload_read_only_flag; | 
 | extern char *nor_cmdline; | 
 | unsigned char nor_flag = 0; | 
 |  | 
 | #ifndef USE_CPPS_KO | 
 | extern unsigned int zOss_NvItemRead(unsigned int NvItemID, unsigned char *NvItemData, unsigned int NvItemLen); | 
 | extern unsigned int zOss_NvItemWrite(unsigned int NvItemID, unsigned char *NvItemData, unsigned int NvItemLen); | 
 | #endif | 
 |  | 
 | /*zdd need modify*/ | 
 | int zDrvNand_ChangeNvrAttr(unsigned int rw ) | 
 | { | 
 |     int ret = 0; | 
 |  //   ret = nand_nv_mid_r_set_to_rw(rw); | 
 | 	return ret; | 
 | } | 
 | EXPORT_SYMBOL(zDrvNand_ChangeNvrAttr); | 
 |  | 
 | /* | 
 | * nv read interface. | 
 | * dwstart: nv addr to read | 
 | * dwLen: length of nv to read | 
 | * to: memory addr | 
 | */ | 
 | int zDrvNand_Read(unsigned int dwStart, unsigned int dwLen, unsigned char* to) | 
 | { | 
 |     int ret = 0; | 
 |  | 
 | 	#ifdef USE_CPPS_KO | 
 | 	ret = cpps_callbacks.zOss_NvItemRead(dwStart, to, dwLen); | 
 | 	#else | 
 | 	ret = zOss_NvItemRead(dwStart, to, dwLen); | 
 |     	#endif | 
 | 		 | 
 | 	return ret; | 
 | } | 
 | EXPORT_SYMBOL(zDrvNand_Read); | 
 |  | 
 | /* | 
 | * nv write interface. | 
 | * dwstart: nv addr to program | 
 | * dwLen: length of nv to program | 
 | * from: memory addr | 
 | */ | 
 | int zDrvNand_Program(unsigned int dwStart, unsigned int dwLen, unsigned char* from) | 
 | { | 
 |     int ret = 0; | 
 |  | 
 | 	#ifdef USE_CPPS_KO | 
 | 	ret = cpps_callbacks.zOss_NvItemWrite(dwStart,from, dwLen); | 
 | 	#else | 
 | 	ret = zOss_NvItemWrite(dwStart,from, dwLen); | 
 | 	#endif | 
 | 	 | 
 | 	return ret; | 
 | } | 
 | EXPORT_SYMBOL(zDrvNand_Program); | 
 |  | 
 | /*zdd need modify*/ | 
 | int zDrvNand_SmsRead(unsigned int dwStart, unsigned int dwLen, unsigned char* to) | 
 | { | 
 |     int ret = 0; | 
 |  | 
 | 	//ret = zftl_wrapper_read((char *)"sms", dwStart, dwLen, to); | 
 |      | 
 | 	return ret; | 
 | } | 
 |  | 
 | /*zdd need modify*/ | 
 | int zDrvNand_SmsProgram(unsigned int dwStart, unsigned int dwLen, unsigned char* from) | 
 | { | 
 |     int ret = 0; | 
 |  | 
 | 	//ret = zftl_wrapper_write((unsigned char *)"sms", dwStart, dwLen, from); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | /*zdd need modify*/ | 
 | int zDrvNand_SimNvRead(unsigned int dwStart, unsigned int dwLen, unsigned char* to) | 
 | { | 
 |     int ret = 0; | 
 | #if 0//fyi   | 
 |     NAND_LOCK | 
 | 	nand_clk_gate(SYSCLK_ENABLE); | 
 |     ret = nand_simnv_read(dwStart, dwLen, to); | 
 | 	nand_clk_gate(SYSCLK_DISABLE); | 
 | 	NAND_UNLOCK | 
 |  | 
 | 	if(ret == -1) | 
 | 	{ | 
 | 		zftl_res = 1; | 
 | 		zDrvNand_SetSimNvFlag(dwStart);/*ECC REBOOT*/ | 
 | 		zftl_res = 0; | 
 | 	} | 
 | #endif | 
 | 	//ret = zftl_wrapper_read((unsigned char *)"simnv", dwStart, dwLen, to); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | /*zdd need modify*/ | 
 | int zDrvNand_SimNvProgram(unsigned int dwStart, unsigned int dwLen, unsigned char* from) | 
 | { | 
 |     int ret = 0; | 
 | #if 0//fyi      | 
 |     NAND_LOCK | 
 | 	nand_clk_gate(SYSCLK_ENABLE); | 
 |     ret = nand_simnv_program(dwStart, dwLen, from); | 
 | 	nand_clk_gate(SYSCLK_DISABLE); | 
 | 	NAND_UNLOCK | 
 | 	if(ret == -1) | 
 | 	{ | 
 | 		zftl_res = 1; | 
 | 		zDrvNand_SetSimNvFlag(dwStart);/*ECC REBOOT*/ | 
 | 		zftl_res = 0; | 
 | 	} | 
 | #endif | 
 | 	//ret = zftl_wrapper_write((unsigned char *)"simnv", dwStart, dwLen, from); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | /*zdd need modify*/ | 
 | int zDrvNand_SimNvFacRead(unsigned int dwStart, unsigned int dwLen, unsigned char* to) | 
 | { | 
 |     int ret = 0; | 
 | #if 0//fyi      | 
 |     NAND_LOCK | 
 | 	nand_clk_gate(SYSCLK_ENABLE); | 
 |     ret = nand_simnvfac_read(dwStart, dwLen, to); | 
 | 	nand_clk_gate(SYSCLK_DISABLE); | 
 | 	NAND_UNLOCK | 
 | #endif | 
 | 	//ret = zftl_wrapper_read((unsigned char *)"simnvfac", dwStart, dwLen, to); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | /*zdd need modify*/ | 
 | int zDrvNand_SimNvFacProgram(unsigned int dwStart, unsigned int dwLen, unsigned char* from) | 
 | { | 
 |     int ret = 0; | 
 | #if 0//fyi   | 
 |     NAND_LOCK | 
 | 	nand_clk_gate(SYSCLK_ENABLE); | 
 |     ret = nand_simnvfac_program(dwStart, dwLen, from); | 
 | 	nand_clk_gate(SYSCLK_DISABLE); | 
 | 	NAND_UNLOCK | 
 | #endif | 
 | 	//ret = zftl_wrapper_write((unsigned char *)"simnvfac", dwStart, dwLen, from); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | /*zdd need modify*/ | 
 | int zDrvNand_NvRwEccMake(unsigned int dwStart, unsigned int dwLen) | 
 | { | 
 |     char buffer[2048]; | 
 | 	 | 
 | 	//if( dwStart >= NVRW_SIZE||dwStart < 0 || (dwStart +dwLen)> NVRW_SIZE|| dwLen > 2048) | 
 |    //     return -1; | 
 | //fyi	nand_nvrw_mid_ecc_make(dwStart,dwLen,buffer); | 
 | 	return 0; | 
 | } | 
 | EXPORT_SYMBOL(zDrvNand_NvRwEccMake); | 
 |  | 
 | /*zdd need modify*/ | 
 | int zDrvNand_EccMake(unsigned char* partName,unsigned int dwStart, unsigned int dwLen) | 
 | { | 
 | 	return 0; | 
 | } | 
 | EXPORT_SYMBOL(zDrvNand_EccMake); | 
 |  | 
 | /* | 
 | * get the bootflag from flash. | 
 | * return: 0, dl off   1, dl on | 
 | */ | 
 | unsigned int zDrvNand_ReadBootflag( void ) | 
 | { | 
 |     unsigned int bootflag = 0; | 
 | 	 | 
 | 	char value = 0; | 
 |     int retlen = 0; | 
 |      | 
 |     unsigned char *buffer = kzalloc(READ_ZLOADER_FLAG_SIZE,GFP_KERNEL); | 
 |     if( buffer == NULL ) | 
 |         return -1; | 
 |  | 
 | 	if(nor_cmdline != NULL) | 
 | 	{ | 
 | 		if (!strcmp(nor_cmdline, "1")) | 
 | 		{ | 
 | 		    nor_flag = 1; | 
 | 			printk("----------EnhancedSecurity---------\n"); | 
 | 		} | 
 | 	} | 
 | 	if(1 == nor_flag) | 
 | 	{ | 
 | #ifndef CONFIG_SPI_ZXIC_NOR | 
 |  | 
 | 		if(nor_read(0, 256, buffer)) | 
 | 	    { | 
 | 	        kfree(buffer); | 
 | 	        return 1; | 
 | 	    } | 
 | 		memcpy(&value, buffer+2, 1);  | 
 | 		bootflag = value; | 
 | 	    | 
 | 	    if( bootflag == 0x5a) | 
 | 	    { | 
 | 	        bootflag = 1; | 
 | 	    } | 
 | 		else | 
 | 		{ | 
 | 	        bootflag = 0; | 
 | 		} | 
 | 	    kfree(buffer); | 
 | #endif | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 		if(mtd_read(mtd_fota,0,READ_ZLOADER_FLAG_SIZE,&retlen,buffer))/* BOOTFLAGÔÚnandµÄµÚ20~27×Ö½Ú */ | 
 | 	    { | 
 | 	        kfree(buffer); | 
 | 	        return 1; | 
 | 	    } | 
 | 		memcpy(&value, buffer+2, 1);  | 
 | 		bootflag = value; | 
 | 	    | 
 | 	    if( bootflag == 0x5a) | 
 | 	    { | 
 | 	        bootflag = 1; | 
 | 	    } | 
 | 		else | 
 | 		{ | 
 | 	        bootflag = 0; | 
 | 		} | 
 | 	    kfree(buffer); | 
 |  | 
 | 	}   | 
 |      | 
 |  | 
 | 	return bootflag; | 
 | } | 
 | EXPORT_SYMBOL(zDrvNand_ReadBootflag); | 
 |  | 
 | /* | 
 | * write the bootflag to flash. | 
 | * flag: 0,dl off   else dl on | 
 | */ | 
 | unsigned int zDrvNand_WriteBootflag(unsigned int flag) | 
 | { | 
 |  | 
 |     unsigned int ret = 0; | 
 | 	char value = 0; | 
 | 	int bootflag = 0; | 
 | 	int retlen = 0; | 
 |     struct erase_info ei; | 
 |  | 
 | 	if(nor_cmdline != NULL) | 
 | 	{ | 
 | 		if (!strcmp(nor_cmdline, "1")) | 
 | 		{ | 
 | 		    nor_flag = 1; | 
 | 			printk("----------EnhancedSecurity---------\n"); | 
 | 		}else{ | 
 | 			printk("----------normal---------\n"); | 
 | 		} | 
 | 	}else{ | 
 | 	    printk("----------nor cmdline is null!---------\n"); | 
 | 	} | 
 |  | 
 | 	if(1 == nor_flag) | 
 | 	{ | 
 | #ifndef CONFIG_SPI_ZXIC_NOR | 
 |  | 
 | 	    unsigned char *buffer = kmalloc(0x10000, GFP_KERNEL); | 
 |  | 
 | 	    if( buffer == NULL ) | 
 | 	        return -1; | 
 | 	 | 
 | 	    if(nor_read(0,0x10000,buffer)) | 
 | 		{ | 
 | 			kfree(buffer); | 
 | 			return -1; | 
 | 		} | 
 | 		if(flag == 0 ) | 
 | 		{ | 
 | 			bootflag = 0x00; | 
 | 			memset(&value, bootflag, 1); | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			bootflag = 0x5a; | 
 | 			memset(&value, bootflag, 1); | 
 | 		} | 
 |  | 
 | 		memcpy(buffer+2, &value, 1); | 
 |  | 
 | 		ret = nor_erase(0); | 
 | 		ret = nor_write(0,0x10000,buffer); | 
 | 		kfree(buffer); | 
 | #endif | 
 | 	} | 
 | 	else | 
 | 	{ | 
 | 	    unsigned char *buffer = kzalloc(WRITE_ZLOADER_FLAG_SIZE,GFP_KERNEL); | 
 |  | 
 | 	    if( buffer == NULL ) | 
 | 	        return -1; | 
 |  | 
 | 	    if(mtd_read(mtd_fota,0,WRITE_ZLOADER_FLAG_SIZE,&retlen,buffer))/* BOOTFLAGÔÚnandµÄµÚ20~27×Ö½Ú */ | 
 | 	    { | 
 | 	        kfree(buffer); | 
 | 	        return -1; | 
 | 	    } | 
 | 		if(flag == 0 ) | 
 | 		{ | 
 | 		    bootflag = 0x00; | 
 | 	        memset(&value, bootflag, 1); | 
 | 		} | 
 | 	    else | 
 | 	    { | 
 | 	        bootflag = 0x5a; | 
 | 	        memset(&value, bootflag, 1); | 
 | 	    } | 
 | 		 | 
 | 	    memcpy(buffer+2, &value, 1); | 
 | 	    memset(&ei, 0, sizeof(struct erase_info)); | 
 | 	    ei.mtd  = mtd_fota; | 
 | 	    ei.addr = 0; | 
 | 	    ei.len  = mtd_fota->erasesize; | 
 | 		g_zload_read_only_flag = 1; | 
 | 	    ret = mtd_erase(mtd_fota, &ei);                  /*²Á³ýµÚÒ»¿é*/ | 
 | 		ret = mtd_write(mtd_fota,0,WRITE_ZLOADER_FLAG_SIZE,&retlen,buffer); | 
 | 		g_zload_read_only_flag = 0; | 
 | 	    kfree(buffer); | 
 |  | 
 | 	}    | 
 |  | 
 |     return 0; | 
 |  | 
 | } | 
 | EXPORT_SYMBOL(zDrvNand_WriteBootflag); | 
 |  | 
 | /* | 
 | * get the usbtimeout flag from flash. | 
 | * return: should be 1~10 | 
 | */ | 
 | unsigned int zDrvNand_ReadUsbtimeout( void ) | 
 | { | 
 |  | 
 |     unsigned int usbtimeout = 0; | 
 | 	char value = 0; | 
 |     int retlen = 0; | 
 |      | 
 |     unsigned char *buffer = kzalloc(READ_ZLOADER_FLAG_SIZE,GFP_KERNEL); | 
 |     if( buffer == NULL ) | 
 |         return -1; | 
 |  | 
 |     if(mtd_read(mtd_fota,0,READ_ZLOADER_FLAG_SIZE,&retlen,buffer))/* BOOTFLAGÔÚnandµÄµÚ20~27×Ö½Ú */ | 
 |     { | 
 |         kfree(buffer); | 
 |         return -1; | 
 |     } | 
 | 	memcpy(&value, buffer+3, 1);  | 
 | 	usbtimeout = value; | 
 | 	 | 
 |     kfree(buffer); | 
 | 	return usbtimeout;    | 
 |  | 
 | } | 
 | EXPORT_SYMBOL(zDrvNand_ReadUsbtimeout); | 
 |  | 
 | /* | 
 | * write the usbtimeout flag to flash. | 
 | * flag: should be 1~10 | 
 | */ | 
 | unsigned int zDrvNand_WriteUsbtimeout( unsigned int flag ) | 
 | { | 
 |  | 
 |     unsigned int ret = 0; | 
 | 	uint8_t oob[256]; | 
 | 	int i =0; | 
 | 	int times = 0; | 
 | 	int retlen = 0; | 
 | 	char value = 0; | 
 | 	struct erase_info ei; | 
 | 	 | 
 |     unsigned char *buffer = kzalloc(WRITE_ZLOADER_FLAG_SIZE,GFP_KERNEL);  /* ZLOADERºÍ·ÖÇø±í¹²8192BYTES */ | 
 |  | 
 | 	if( buffer == NULL ) | 
 |         return -1; | 
 |  | 
 |     if(mtd_read(mtd_fota,0,WRITE_ZLOADER_FLAG_SIZE,&retlen,buffer))/* BOOTFLAGÔÚnandµÄµÚ20~27×Ö½Ú */ | 
 |     { | 
 |         kfree(buffer); | 
 |         return -1; | 
 |     } | 
 |      | 
 |     memset(&value, flag, 1); | 
 |     memcpy(buffer+3, &value, 1); | 
 |  | 
 | 	memset(&ei, 0, sizeof(struct erase_info)); | 
 |     ei.mtd  = mtd_fota; | 
 |     ei.addr = 0; | 
 |     ei.len  = mtd_fota->erasesize; | 
 | 	g_zload_read_only_flag = 1; | 
 |     ret = mtd_erase(mtd_fota, &ei);                  /*²Á³ýµÚÒ»¿é*/ | 
 | 	ret = mtd_write(mtd_fota,0,WRITE_ZLOADER_FLAG_SIZE,&retlen,buffer); | 
 | 	g_zload_read_only_flag = 0; | 
 |     kfree(buffer); | 
 |    		 | 
 | 	return ret;  | 
 | } | 
 | EXPORT_SYMBOL(zDrvNand_WriteUsbtimeout); | 
 |  |