mirror of https://github.com/OpenIPC/firmware.git
				
				
				
			[Gk7205v200] SPI NOR force global unlock and SR clear (#649)
							parent
							
								
									cee839f5b1
								
							
						
					
					
						commit
						fb57f360f6
					
				|  | @ -0,0 +1,211 @@ | ||||||
|  | --- a/drivers/mtd/spi-nor/spi-nor.c
 | ||||||
|  | +++ b/drivers/mtd/spi-nor/spi-nor.c
 | ||||||
|  | @@ -107,6 +107,34 @@
 | ||||||
|  |  	return val; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static int read_sr2(struct spi_nor *nor)
 | ||||||
|  | +{
 | ||||||
|  | +	int ret;
 | ||||||
|  | +	u8 val;
 | ||||||
|  | +
 | ||||||
|  | +	ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &val, 1);
 | ||||||
|  | +	if (ret < 0) {
 | ||||||
|  | +		pr_err("error %d reading SR2\n", (int) ret);
 | ||||||
|  | +		return ret;
 | ||||||
|  | +	}
 | ||||||
|  | +
 | ||||||
|  | +	return val;
 | ||||||
|  | +}
 | ||||||
|  | +
 | ||||||
|  | +static int read_sr3(struct spi_nor *nor)
 | ||||||
|  | +{
 | ||||||
|  | +	int ret;
 | ||||||
|  | +	u8 val;
 | ||||||
|  | +
 | ||||||
|  | +	ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &val, 1);
 | ||||||
|  | +	if (ret < 0) {
 | ||||||
|  | +		pr_err("error %d reading SR3\n", (int) ret);
 | ||||||
|  | +		return ret;
 | ||||||
|  | +	}
 | ||||||
|  | +
 | ||||||
|  | +	return val;
 | ||||||
|  | +}
 | ||||||
|  | +
 | ||||||
|  |  /* | ||||||
|  |   * Read the flag status register, returning its value in the location | ||||||
|  |   * Return the status register value. | ||||||
|  | @@ -166,6 +194,12 @@
 | ||||||
|  |  	return nor->write_reg(nor, SPINOR_OP_WRSR2, nor->cmd_buf, 1); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static inline int write_sr3(struct spi_nor *nor, u8 val)
 | ||||||
|  | +{
 | ||||||
|  | +	nor->cmd_buf[0] = val;
 | ||||||
|  | +	return nor->write_reg(nor, SPINOR_OP_WRSR3, nor->cmd_buf, 1);
 | ||||||
|  | +}
 | ||||||
|  | +
 | ||||||
|  |  /* | ||||||
|  |   * Set write enable latch with Write Enable command. | ||||||
|  |   * Returns negative if error occurred. | ||||||
|  | @@ -2178,7 +2212,7 @@
 | ||||||
|  |   | ||||||
|  |  	if (!nor->level) { | ||||||
|  |  		nor->end_addr = 0; | ||||||
|  | -		dev_warn(nor->dev, "all blocks is unlocked.\n");
 | ||||||
|  | +		dev_warn(nor->dev, "all blocks are unlocked.\n");
 | ||||||
|  |  		return; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | @@ -2261,6 +2295,48 @@
 | ||||||
|  |  	return level; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static void bsp_global_unlock(struct spi_nor *nor) {
 | ||||||
|  | +	int val;
 | ||||||
|  | +
 | ||||||
|  | +	dev_info(nor->dev, "Force global unlock\n");
 | ||||||
|  | +	write_enable(nor);
 | ||||||
|  | +	/* Global Block/Sector Unlock,
 | ||||||
|  | +	* see 8.2.42 Global Block/Sector Unlock (98h) */
 | ||||||
|  | +	nor->write_reg(nor, 0x98, NULL, 0);
 | ||||||
|  | +	spi_nor_wait_till_ready(nor);
 | ||||||
|  | +
 | ||||||
|  | +	val = read_sr(nor);
 | ||||||
|  | +	if (val){
 | ||||||
|  | +		dev_info(nor->dev, "SR1:[%02x]->[00] ", val);
 | ||||||
|  | +		val=0;
 | ||||||
|  | +		write_enable(nor);
 | ||||||
|  | +		write_sr(nor, val);
 | ||||||
|  | +		if(spi_nor_wait_till_ready(nor))
 | ||||||
|  | +			dev_err(nor->dev, "error while writing SR1.\n");
 | ||||||
|  | +	}
 | ||||||
|  | +
 | ||||||
|  | +	val = read_sr2(nor);
 | ||||||
|  | +	if (val){
 | ||||||
|  | +		dev_info(nor->dev, "SR2:[%02x]->[00]", val);
 | ||||||
|  | +		val = 0;
 | ||||||
|  | +		write_enable(nor);
 | ||||||
|  | +		write_sr2(nor, val);
 | ||||||
|  | +		if(spi_nor_wait_till_ready(nor))
 | ||||||
|  | +			dev_err(nor->dev, "error while writing SR2.\n");
 | ||||||
|  | +	}
 | ||||||
|  | +
 | ||||||
|  | +	val = read_sr3(nor);
 | ||||||
|  | +	if (val & 4){
 | ||||||
|  | +		dev_info(nor->dev, "SR3:[%02x]->[%02x]", val, val ^ 4);
 | ||||||
|  | +		val ^= 4; // Remove SR3_WPS
 | ||||||
|  | +		write_enable(nor);
 | ||||||
|  | +		write_sr3(nor, val);
 | ||||||
|  | +		if(spi_nor_wait_till_ready(nor))
 | ||||||
|  | +			dev_err(nor->dev, "error while writing SR3.\n");
 | ||||||
|  | +	}
 | ||||||
|  | +
 | ||||||
|  | +}
 | ||||||
|  | +
 | ||||||
|  |  static void bsp_get_spi_lock_info(struct spi_nor *nor, const struct flash_info *info) | ||||||
|  |  { | ||||||
|  |  	unsigned int chipsize; | ||||||
|  | @@ -2275,18 +2351,12 @@
 | ||||||
|  |  	case SNOR_MFR_ESMT: | ||||||
|  |  	case SNOR_MFR_EON: | ||||||
|  |  	case SNOR_MFR_SPANSION: | ||||||
|  | +		bsp_global_unlock(nor);
 | ||||||
|  |  		/* BP bit convert to lock level */ | ||||||
|  |  		nor->level = bsp_bp_to_level(nor, info, BP_NUM_3); | ||||||
|  |  		break; | ||||||
|  |  	case SNOR_MFR_WINBOND: | ||||||
|  | -		if (!strcmp("w25q128(b/f)v", info->name)) {
 | ||||||
|  | -			dev_info(nor->dev, "Force global unlock\n");
 | ||||||
|  | -			write_enable(nor);
 | ||||||
|  | -			/* Global Block/Sector Unlock,
 | ||||||
|  | -			 * see 8.2.42 Global Block/Sector Unlock (98h) */
 | ||||||
|  | -			nor->write_reg(nor, 0x98, NULL, 0);
 | ||||||
|  | -			write_disable(nor);
 | ||||||
|  | -		}
 | ||||||
|  | +		bsp_global_unlock(nor);
 | ||||||
|  |  		/* BP bit convert to lock level */ | ||||||
|  |  		if (chipsize <= _16M) | ||||||
|  |  			nor->level = bsp_bp_to_level(nor, info, BP_NUM_3); | ||||||
|  | @@ -2294,7 +2364,8 @@
 | ||||||
|  |  			nor->level = bsp_bp_to_level(nor, info, BP_NUM_4); | ||||||
|  |  		break; | ||||||
|  |  	case SNOR_MFR_MACRONIX: | ||||||
|  | -	
 | ||||||
|  | +	case SNOR_MFR_XMC:
 | ||||||
|  | +		bsp_global_unlock(nor);
 | ||||||
|  |  		/* BP bit convert to lock level */ | ||||||
|  |  		if (chipsize <= _8M) | ||||||
|  |  			nor->level = bsp_bp_to_level(nor, info, BP_NUM_3); | ||||||
|  | @@ -2302,6 +2373,7 @@
 | ||||||
|  |  			nor->level = bsp_bp_to_level(nor, info, BP_NUM_4); | ||||||
|  |  		break; | ||||||
|  |  	case SNOR_MFR_XTX: | ||||||
|  | +		bsp_global_unlock(nor);
 | ||||||
|  |  		/* BP bit convert to lock level */ | ||||||
|  |  		nor->level = bsp_bp_to_level(nor, info, BP_NUM_4); | ||||||
|  |  		break; | ||||||
|  | @@ -2562,6 +2634,8 @@
 | ||||||
|  |  { | ||||||
|  |  	int ret; | ||||||
|  |  	unsigned char cval,val; | ||||||
|  | +	unsigned char sr1, sr2, sr3;
 | ||||||
|  | +	char sr1txt[256] = {0}, sr2txt[256] = {0}, sr3txt[256] = {0};
 | ||||||
|  |   | ||||||
|  |  	if (JEDEC_MFR(info) == SNOR_MFR_MACRONIX){ | ||||||
|  |  		val = read_sr(nor); | ||||||
|  | @@ -2583,26 +2657,24 @@
 | ||||||
|  |  			nor->cmd_buf[1]=(cval & (~CR_DUMMY_CYCLE)); | ||||||
|  |  			ret = nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2); | ||||||
|  |  		} | ||||||
|  | -	} else if (JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
 | ||||||
|  | -		unsigned char sr1, sr2, sr3;
 | ||||||
|  | -		char sr1txt[256] = {0}, sr2txt[256] = {0}, sr3txt[256] = {0};
 | ||||||
|  | -
 | ||||||
|  | -		sr1 = read_sr(nor);
 | ||||||
|  | -		if (sr1 < 0)
 | ||||||
|  | -			return sr1;
 | ||||||
|  | -		ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1);
 | ||||||
|  | -		if(ret < 0){
 | ||||||
|  | -			dev_err(nor->dev, "error %d reading config Reg.\n", ret);
 | ||||||
|  | -			return ret;
 | ||||||
|  | -		}
 | ||||||
|  | -		ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &sr3, 1);
 | ||||||
|  | -		if(ret < 0){
 | ||||||
|  | -			dev_err(nor->dev, "error %d reading config Reg.\n", ret);
 | ||||||
|  | -			return ret;
 | ||||||
|  | -		}
 | ||||||
|  | -		dev_info(nor->dev, "Winbond: SR1 [%s], SR2 [%s], SR3 [%s]\n",
 | ||||||
|  | -				winbond_sr1txt(sr1txt, sr1), winbond_sr2txt(sr2txt, sr2),
 | ||||||
|  | -				winbond_sr3txt(sr3txt, sr3));
 | ||||||
|  | +	}
 | ||||||
|  | +
 | ||||||
|  | +	sr1 = read_sr(nor);
 | ||||||
|  | +	if (sr1 < 0)
 | ||||||
|  | +		return sr1;
 | ||||||
|  | +	sr2 = read_sr2(nor);
 | ||||||
|  | +	if (sr2 < 0)
 | ||||||
|  | +		return sr2;
 | ||||||
|  | +	sr3 = read_sr3(nor);
 | ||||||
|  | +	if (sr3 < 0)
 | ||||||
|  | +		return sr3;
 | ||||||
|  | +	if (JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
 | ||||||
|  | +	dev_info(nor->dev, "Winbond: SR1 [%s], SR2 [%s], SR3 [%s]\n",
 | ||||||
|  | +			winbond_sr1txt(sr1txt, sr1), winbond_sr2txt(sr2txt, sr2),
 | ||||||
|  | +			winbond_sr3txt(sr3txt, sr3));
 | ||||||
|  | +	} else {
 | ||||||
|  | +	dev_info(nor->dev, "SR1 [%02x], SR2 [%02x], SR3 [%02x]\n",
 | ||||||
|  | +			sr1, sr2, sr3);
 | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  |  	if (params) { | ||||||
|  | --- a/include/linux/mtd/spi-nor.h
 | ||||||
|  | +++ b/include/linux/mtd/spi-nor.h
 | ||||||
|  | @@ -30,6 +30,7 @@
 | ||||||
|  |  #define SNOR_MFR_ESMT		0x8c | ||||||
|  |  #define SNOR_MFR_GD			0xc8 | ||||||
|  |  #define SNOR_MFR_XTX        0x0b | ||||||
|  | +#define SNOR_MFR_XMC        0x20
 | ||||||
|  |  #define SNOR_MFR_PUYA       0x85 | ||||||
|  |  #define SNOR_MFR_FM         0xa1 | ||||||
|  |  #define SNOR_MFR_ISSI		0x9d | ||||||
		Loading…
	
		Reference in New Issue