mirror of https://github.com/OpenIPC/firmware.git
				
				
				
			[Hi3516ev200] SPI NOR force global unlock and SR clear (#650)
							parent
							
								
									bb1d26b51b
								
							
						
					
					
						commit
						434e00fef6
					
				|  | @ -0,0 +1,196 @@ | |||
| --- 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. | ||||
| @@ -155,6 +183,18 @@
 | ||||
|  	return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1); | ||||
|  } | ||||
|   | ||||
| +static inline int write_sr2(struct spi_nor *nor, u8 val)
 | ||||
| +{
 | ||||
| +	nor->cmd_buf[0] = val;
 | ||||
| +	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. | ||||
| @@ -1964,7 +2004,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; | ||||
|  	} | ||||
|   | ||||
| @@ -2047,6 +2087,47 @@
 | ||||
|  	return level; | ||||
|  } | ||||
|   | ||||
| +static void hisi_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 hisi_get_spi_lock_info(struct spi_nor *nor, const struct flash_info *info) | ||||
|  { | ||||
|  	unsigned int chipsize; | ||||
| @@ -2057,6 +2138,7 @@
 | ||||
|  	/* read the BP bit in RDSR to check whether nor is lock or not */ | ||||
|  	switch (JEDEC_MFR(info)) { | ||||
|  	case SNOR_MFR_GD: | ||||
| +	case SNOR_MFR_FM:
 | ||||
|  	case SNOR_MFR_ESMT: | ||||
|  	case SNOR_MFR_EON: | ||||
|  	case SNOR_MFR_SPANSION: | ||||
| @@ -2064,7 +2146,6 @@
 | ||||
|  		nor->level = hisi_bp_to_level(nor, info, BP_NUM_3); | ||||
|  		break; | ||||
|  	case SNOR_MFR_WINBOND: | ||||
| -	case SNOR_MFR_XTX:
 | ||||
|  		/* BP bit convert to lock level */ | ||||
|  		if (chipsize <= _16M) | ||||
|  			nor->level = hisi_bp_to_level(nor, info, BP_NUM_3); | ||||
| @@ -2072,16 +2153,23 @@
 | ||||
|  			nor->level = hisi_bp_to_level(nor, info, BP_NUM_4); | ||||
|  		break; | ||||
|  	case SNOR_MFR_MACRONIX: | ||||
| +	case SNOR_MFR_XMC:
 | ||||
|  		/* BP bit convert to lock level */ | ||||
|  		if (chipsize <= _8M) | ||||
|  			nor->level = hisi_bp_to_level(nor, info, BP_NUM_3); | ||||
|  		else | ||||
|  			nor->level = hisi_bp_to_level(nor, info, BP_NUM_4); | ||||
|  		break; | ||||
| +	case SNOR_MFR_XTX:
 | ||||
| +		/* BP bit convert to lock level */
 | ||||
| +		nor->level = hisi_bp_to_level(nor, info, BP_NUM_4);
 | ||||
| +		break;
 | ||||
|  	default: | ||||
|  		goto usage; | ||||
|  	} | ||||
|   | ||||
| +	hisi_global_unlock(nor);
 | ||||
| +
 | ||||
|  	spi_lock_update_address(nor, info); | ||||
|  	if (nor->end_addr) | ||||
|  		dev_info(dev, "Address range [0 => %#x] is locked.\n", | ||||
| @@ -2245,6 +2333,7 @@
 | ||||
|  { | ||||
|  	int ret; | ||||
|  	unsigned char cval,val; | ||||
| +	unsigned char sr1, sr2, sr3;
 | ||||
|   | ||||
|  	if (JEDEC_MFR(info) == SNOR_MFR_MACRONIX){ | ||||
|  		val = read_sr(nor); | ||||
| @@ -2268,7 +2357,18 @@
 | ||||
|  		} | ||||
|  	} | ||||
|   | ||||
| -	if (params) {
 | ||||
| +	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;
 | ||||
| +	dev_info(nor->dev, "SR1 [%02x], SR2 [%02x], SR3 [%02x]\n", sr1, sr2, sr3);
 | ||||
| +
 | ||||
| +        if (params) {
 | ||||
|  		ret = spi_nor_setup(nor, info, params, modes); | ||||
|  		if (ret) | ||||
|  			return ret; | ||||
| --- a/include/linux/mtd/spi-nor.h
 | ||||
| +++ b/include/linux/mtd/spi-nor.h
 | ||||
| @@ -28,8 +28,10 @@
 | ||||
|  #define SNOR_MFR_EON		CFI_MFR_EON | ||||
|  #define SNOR_MFR_WINBOND	0xef | ||||
|  #define SNOR_MFR_ESMT		0x8c | ||||
| -#define SNOR_MFR_GD			0xc8
 | ||||
| -#define SNOR_MFR_XTX        0x0b
 | ||||
| +#define SNOR_MFR_GD		0xc8
 | ||||
| +#define SNOR_MFR_FM		0xa1
 | ||||
| +#define SNOR_MFR_XTX		0x0b
 | ||||
| +#define SNOR_MFR_XMC		0x20
 | ||||
|   | ||||
|  /* Flash set the RESET# from */ | ||||
|  #define SPI_NOR_SR_RST_MASK	BIT(7) | ||||
		Loading…
	
		Reference in New Issue