diff mbox

[v2] mtd: brcmnand: Add v7.2 controller support

Message ID 1464715383-26053-1-git-send-email-f.fainelli@gmail.com
State Not Applicable, archived
Headers show

Commit Message

Florian Fainelli May 31, 2016, 5:23 p.m. UTC
The 7.2 controller differs in a few area compared to its predecssor (7.1):

- NAND scrambler, which we are not using just yet
- higher ECC levels (up to 120 bits) per 1KB data blocks, also not supported yet
- up to 128B OOB

This patchs adds the ncessary code to support such a controller
generation and updates the Device Tree binding.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v2:

- fixed a bunch of conditionals on the versions which should
  have been exclusive (spotted by Thomas)

 .../devicetree/bindings/mtd/brcm,brcmnand.txt      |  1 +
 drivers/mtd/nand/brcmnand/brcmnand.c               | 91 ++++++++++++++++++----
 2 files changed, 78 insertions(+), 14 deletions(-)

Comments

Boris Brezillon June 2, 2016, 5:13 p.m. UTC | #1
On Tue, 31 May 2016 10:23:02 -0700
Florian Fainelli <f.fainelli@gmail.com> wrote:

> The 7.2 controller differs in a few area compared to its predecssor (7.1):
> 
> - NAND scrambler, which we are not using just yet
> - higher ECC levels (up to 120 bits) per 1KB data blocks, also not supported yet
> - up to 128B OOB
> 
> This patchs adds the ncessary code to support such a controller
> generation and updates the Device Tree binding.
> 

This patch looks good to me. Brian, Kamal, do you want to add your ack?

> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
> Changes in v2:
> 
> - fixed a bunch of conditionals on the versions which should
>   have been exclusive (spotted by Thomas)
> 
>  .../devicetree/bindings/mtd/brcm,brcmnand.txt      |  1 +
>  drivers/mtd/nand/brcmnand/brcmnand.c               | 91 ++++++++++++++++++----
>  2 files changed, 78 insertions(+), 14 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
> index deb24cbdda82..c8d71e75cb09 100644
> --- a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
> +++ b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
> @@ -27,6 +27,7 @@ Required properties:
>                           brcm,brcmnand-v6.2
>                           brcm,brcmnand-v7.0
>                           brcm,brcmnand-v7.1
> +                         brcm,brcmnand-v7.2
>                           brcm,brcmnand
>  - reg              : the register start and length for NAND register region.
>                       (optional) Flash DMA register range (if present)
> diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
> index b76ad7c0144f..0a54a0f5a4b1 100644
> --- a/drivers/mtd/nand/brcmnand/brcmnand.c
> +++ b/drivers/mtd/nand/brcmnand/brcmnand.c
> @@ -340,6 +340,36 @@ static const u16 brcmnand_regs_v71[] = {
>  	[BRCMNAND_FC_BASE]		= 0x400,
>  };
>  
> +/* BRCMNAND v7.2 */
> +static const u16 brcmnand_regs_v72[] = {
> +	[BRCMNAND_CMD_START]		=  0x04,
> +	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
> +	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
> +	[BRCMNAND_INTFC_STATUS]		=  0x14,
> +	[BRCMNAND_CS_SELECT]		=  0x18,
> +	[BRCMNAND_CS_XOR]		=  0x1c,
> +	[BRCMNAND_LL_OP]		=  0x20,
> +	[BRCMNAND_CS0_BASE]		=  0x50,
> +	[BRCMNAND_CS1_BASE]		=     0,
> +	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
> +	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
> +	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
> +	[BRCMNAND_CORR_COUNT]		= 0x100,
> +	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
> +	[BRCMNAND_CORR_ADDR]		= 0x110,
> +	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
> +	[BRCMNAND_UNCORR_ADDR]		= 0x118,
> +	[BRCMNAND_SEMAPHORE]		= 0x150,
> +	[BRCMNAND_ID]			= 0x194,
> +	[BRCMNAND_ID_EXT]		= 0x198,
> +	[BRCMNAND_LL_RDATA]		= 0x19c,
> +	[BRCMNAND_OOB_READ_BASE]	= 0x200,
> +	[BRCMNAND_OOB_READ_10_BASE]	=     0,
> +	[BRCMNAND_OOB_WRITE_BASE]	= 0x400,
> +	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
> +	[BRCMNAND_FC_BASE]		= 0x600,
> +};
> +
>  enum brcmnand_cs_reg {
>  	BRCMNAND_CS_CFG_EXT = 0,
>  	BRCMNAND_CS_CFG,
> @@ -435,7 +465,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
>  	}
>  
>  	/* Register offsets */
> -	if (ctrl->nand_version >= 0x0701)
> +	if (ctrl->nand_version >= 0x0702)
> +		ctrl->reg_offsets = brcmnand_regs_v72;
> +	else if (ctrl->nand_version >= 0x0701)
>  		ctrl->reg_offsets = brcmnand_regs_v71;
>  	else if (ctrl->nand_version >= 0x0600)
>  		ctrl->reg_offsets = brcmnand_regs_v60;
> @@ -480,7 +512,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
>  	}
>  
>  	/* Maximum spare area sector size (per 512B) */
> -	if (ctrl->nand_version >= 0x0600)
> +	if (ctrl->nand_version >= 0x0702)
> +		ctrl->max_oob = 128;
> +	else if (ctrl->nand_version >= 0x0600)
>  		ctrl->max_oob = 64;
>  	else if (ctrl->nand_version >= 0x0500)
>  		ctrl->max_oob = 32;
> @@ -583,14 +617,20 @@ static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
>  	enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
>  	int cs = host->cs;
>  
> -	if (ctrl->nand_version >= 0x0600)
> +	if (ctrl->nand_version >= 0x0702)
> +		bits = 7;
> +	else if (ctrl->nand_version >= 0x0600)
>  		bits = 6;
>  	else if (ctrl->nand_version >= 0x0500)
>  		bits = 5;
>  	else
>  		bits = 4;
>  
> -	if (ctrl->nand_version >= 0x0600) {
> +	if (ctrl->nand_version >= 0x0702) {
> +		if (cs >= 4)
> +			reg = BRCMNAND_CORR_THRESHOLD_EXT;
> +		shift = (cs % 4) * bits;
> +	} else if (ctrl->nand_version >= 0x0600) {
>  		if (cs >= 5)
>  			reg = BRCMNAND_CORR_THRESHOLD_EXT;
>  		shift = (cs % 5) * bits;
> @@ -631,19 +671,28 @@ enum {
>  
>  static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
>  {
> -	if (ctrl->nand_version >= 0x0600)
> +	if (ctrl->nand_version >= 0x0702)
> +		return GENMASK(7, 0);
> +	else if (ctrl->nand_version >= 0x0600)
>  		return GENMASK(6, 0);
>  	else
>  		return GENMASK(5, 0);
>  }
>  
>  #define NAND_ACC_CONTROL_ECC_SHIFT	16
> +#define NAND_ACC_CONTROL_ECC_EXT_SHIFT	13
>  
>  static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
>  {
>  	u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
>  
> -	return mask << NAND_ACC_CONTROL_ECC_SHIFT;
> +	mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
> +
> +	/* v7.2 includes additional ECC levels */
> +	if (ctrl->nand_version >= 0x0702)
> +		mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
> +
> +	return mask;
>  }
>  
>  static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
> @@ -667,7 +716,9 @@ static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
>  
>  static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
>  {
> -	if (ctrl->nand_version >= 0x0600)
> +	if (ctrl->nand_version >= 0x0702)
> +		return 9;
> +	else if (ctrl->nand_version >= 0x0600)
>  		return 7;
>  	else if (ctrl->nand_version >= 0x0500)
>  		return 6;
> @@ -773,10 +824,16 @@ enum brcmnand_llop_type {
>   * Internal support functions
>   ***********************************************************************/
>  
> -static inline bool is_hamming_ecc(struct brcmnand_cfg *cfg)
> +static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
> +				  struct brcmnand_cfg *cfg)
>  {
> -	return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
> -		cfg->ecc_level == 15;
> +	if (ctrl->nand_version <= 0x0701)
> +		return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
> +			cfg->ecc_level == 15;
> +	else
> +		return cfg->sector_size_1k == 0 && ((cfg->spare_area_size == 16 &&
> +			cfg->ecc_level == 15) ||
> +			(cfg->spare_area_size == 28 && cfg->ecc_level == 16));
>  }
>  
>  /*
> @@ -931,7 +988,7 @@ static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
>  	if (p->sector_size_1k)
>  		ecc_level <<= 1;
>  
> -	if (is_hamming_ecc(p)) {
> +	if (is_hamming_ecc(host->ctrl, p)) {
>  		ecc->bytes = 3 * sectors;
>  		mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
>  		return 0;
> @@ -1857,7 +1914,8 @@ static int brcmnand_set_cfg(struct brcmnand_host *host,
>  	return 0;
>  }
>  
> -static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
> +static void brcmnand_print_cfg(struct brcmnand_host *host,
> +			       char *buf, struct brcmnand_cfg *cfg)
>  {
>  	buf += sprintf(buf,
>  		"%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
> @@ -1868,7 +1926,7 @@ static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
>  		cfg->spare_area_size, cfg->device_width);
>  
>  	/* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
> -	if (is_hamming_ecc(cfg))
> +	if (is_hamming_ecc(host->ctrl, cfg))
>  		sprintf(buf, ", Hamming ECC");
>  	else if (cfg->sector_size_1k)
>  		sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
> @@ -1987,7 +2045,7 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
>  
>  	brcmnand_set_ecc_enabled(host, 1);
>  
> -	brcmnand_print_cfg(msg, cfg);
> +	brcmnand_print_cfg(host, msg, cfg);
>  	dev_info(ctrl->dev, "detected %s\n", msg);
>  
>  	/* Configure ACC_CONTROL */
> @@ -1995,6 +2053,10 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
>  	tmp = nand_readreg(ctrl, offs);
>  	tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
>  	tmp &= ~ACC_CONTROL_RD_ERASED;
> +
> +	/* We need to turn on Read from erased paged protected by ECC */
> +	if (ctrl->nand_version >= 0x0702)
> +		tmp |= ACC_CONTROL_RD_ERASED;
>  	tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
>  	if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
>  		/*
> @@ -2195,6 +2257,7 @@ static const struct of_device_id brcmnand_of_match[] = {
>  	{ .compatible = "brcm,brcmnand-v6.2" },
>  	{ .compatible = "brcm,brcmnand-v7.0" },
>  	{ .compatible = "brcm,brcmnand-v7.1" },
> +	{ .compatible = "brcm,brcmnand-v7.2" },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, brcmnand_of_match);
Kamal Dasu June 2, 2016, 7:36 p.m. UTC | #2
This patch looks good to me.

Acked-by: Kamal Dasu <kdasu.kdev@gmail.com>

Thanks
Kamal

On Thu, Jun 2, 2016 at 1:13 PM, Boris Brezillon
<boris.brezillon@free-electrons.com> wrote:
> On Tue, 31 May 2016 10:23:02 -0700
> Florian Fainelli <f.fainelli@gmail.com> wrote:
>
>> The 7.2 controller differs in a few area compared to its predecssor (7.1):
>>
>> - NAND scrambler, which we are not using just yet
>> - higher ECC levels (up to 120 bits) per 1KB data blocks, also not supported yet
>> - up to 128B OOB
>>
>> This patchs adds the ncessary code to support such a controller
>> generation and updates the Device Tree binding.
>>
>
> This patch looks good to me. Brian, Kamal, do you want to add your ack?
>
>> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
>> ---
>> Changes in v2:
>>
>> - fixed a bunch of conditionals on the versions which should
>>   have been exclusive (spotted by Thomas)
>>
>>  .../devicetree/bindings/mtd/brcm,brcmnand.txt      |  1 +
>>  drivers/mtd/nand/brcmnand/brcmnand.c               | 91 ++++++++++++++++++----
>>  2 files changed, 78 insertions(+), 14 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
>> index deb24cbdda82..c8d71e75cb09 100644
>> --- a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
>> +++ b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
>> @@ -27,6 +27,7 @@ Required properties:
>>                           brcm,brcmnand-v6.2
>>                           brcm,brcmnand-v7.0
>>                           brcm,brcmnand-v7.1
>> +                         brcm,brcmnand-v7.2
>>                           brcm,brcmnand
>>  - reg              : the register start and length for NAND register region.
>>                       (optional) Flash DMA register range (if present)
>> diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
>> index b76ad7c0144f..0a54a0f5a4b1 100644
>> --- a/drivers/mtd/nand/brcmnand/brcmnand.c
>> +++ b/drivers/mtd/nand/brcmnand/brcmnand.c
>> @@ -340,6 +340,36 @@ static const u16 brcmnand_regs_v71[] = {
>>       [BRCMNAND_FC_BASE]              = 0x400,
>>  };
>>
>> +/* BRCMNAND v7.2 */
>> +static const u16 brcmnand_regs_v72[] = {
>> +     [BRCMNAND_CMD_START]            =  0x04,
>> +     [BRCMNAND_CMD_EXT_ADDRESS]      =  0x08,
>> +     [BRCMNAND_CMD_ADDRESS]          =  0x0c,
>> +     [BRCMNAND_INTFC_STATUS]         =  0x14,
>> +     [BRCMNAND_CS_SELECT]            =  0x18,
>> +     [BRCMNAND_CS_XOR]               =  0x1c,
>> +     [BRCMNAND_LL_OP]                =  0x20,
>> +     [BRCMNAND_CS0_BASE]             =  0x50,
>> +     [BRCMNAND_CS1_BASE]             =     0,
>> +     [BRCMNAND_CORR_THRESHOLD]       =  0xdc,
>> +     [BRCMNAND_CORR_THRESHOLD_EXT]   =  0xe0,
>> +     [BRCMNAND_UNCORR_COUNT]         =  0xfc,
>> +     [BRCMNAND_CORR_COUNT]           = 0x100,
>> +     [BRCMNAND_CORR_EXT_ADDR]        = 0x10c,
>> +     [BRCMNAND_CORR_ADDR]            = 0x110,
>> +     [BRCMNAND_UNCORR_EXT_ADDR]      = 0x114,
>> +     [BRCMNAND_UNCORR_ADDR]          = 0x118,
>> +     [BRCMNAND_SEMAPHORE]            = 0x150,
>> +     [BRCMNAND_ID]                   = 0x194,
>> +     [BRCMNAND_ID_EXT]               = 0x198,
>> +     [BRCMNAND_LL_RDATA]             = 0x19c,
>> +     [BRCMNAND_OOB_READ_BASE]        = 0x200,
>> +     [BRCMNAND_OOB_READ_10_BASE]     =     0,
>> +     [BRCMNAND_OOB_WRITE_BASE]       = 0x400,
>> +     [BRCMNAND_OOB_WRITE_10_BASE]    =     0,
>> +     [BRCMNAND_FC_BASE]              = 0x600,
>> +};
>> +
>>  enum brcmnand_cs_reg {
>>       BRCMNAND_CS_CFG_EXT = 0,
>>       BRCMNAND_CS_CFG,
>> @@ -435,7 +465,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
>>       }
>>
>>       /* Register offsets */
>> -     if (ctrl->nand_version >= 0x0701)
>> +     if (ctrl->nand_version >= 0x0702)
>> +             ctrl->reg_offsets = brcmnand_regs_v72;
>> +     else if (ctrl->nand_version >= 0x0701)
>>               ctrl->reg_offsets = brcmnand_regs_v71;
>>       else if (ctrl->nand_version >= 0x0600)
>>               ctrl->reg_offsets = brcmnand_regs_v60;
>> @@ -480,7 +512,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
>>       }
>>
>>       /* Maximum spare area sector size (per 512B) */
>> -     if (ctrl->nand_version >= 0x0600)
>> +     if (ctrl->nand_version >= 0x0702)
>> +             ctrl->max_oob = 128;
>> +     else if (ctrl->nand_version >= 0x0600)
>>               ctrl->max_oob = 64;
>>       else if (ctrl->nand_version >= 0x0500)
>>               ctrl->max_oob = 32;
>> @@ -583,14 +617,20 @@ static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
>>       enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
>>       int cs = host->cs;
>>
>> -     if (ctrl->nand_version >= 0x0600)
>> +     if (ctrl->nand_version >= 0x0702)
>> +             bits = 7;
>> +     else if (ctrl->nand_version >= 0x0600)
>>               bits = 6;
>>       else if (ctrl->nand_version >= 0x0500)
>>               bits = 5;
>>       else
>>               bits = 4;
>>
>> -     if (ctrl->nand_version >= 0x0600) {
>> +     if (ctrl->nand_version >= 0x0702) {
>> +             if (cs >= 4)
>> +                     reg = BRCMNAND_CORR_THRESHOLD_EXT;
>> +             shift = (cs % 4) * bits;
>> +     } else if (ctrl->nand_version >= 0x0600) {
>>               if (cs >= 5)
>>                       reg = BRCMNAND_CORR_THRESHOLD_EXT;
>>               shift = (cs % 5) * bits;
>> @@ -631,19 +671,28 @@ enum {
>>
>>  static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
>>  {
>> -     if (ctrl->nand_version >= 0x0600)
>> +     if (ctrl->nand_version >= 0x0702)
>> +             return GENMASK(7, 0);
>> +     else if (ctrl->nand_version >= 0x0600)
>>               return GENMASK(6, 0);
>>       else
>>               return GENMASK(5, 0);
>>  }
>>
>>  #define NAND_ACC_CONTROL_ECC_SHIFT   16
>> +#define NAND_ACC_CONTROL_ECC_EXT_SHIFT       13
>>
>>  static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
>>  {
>>       u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
>>
>> -     return mask << NAND_ACC_CONTROL_ECC_SHIFT;
>> +     mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
>> +
>> +     /* v7.2 includes additional ECC levels */
>> +     if (ctrl->nand_version >= 0x0702)
>> +             mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
>> +
>> +     return mask;
>>  }
>>
>>  static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
>> @@ -667,7 +716,9 @@ static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
>>
>>  static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
>>  {
>> -     if (ctrl->nand_version >= 0x0600)
>> +     if (ctrl->nand_version >= 0x0702)
>> +             return 9;
>> +     else if (ctrl->nand_version >= 0x0600)
>>               return 7;
>>       else if (ctrl->nand_version >= 0x0500)
>>               return 6;
>> @@ -773,10 +824,16 @@ enum brcmnand_llop_type {
>>   * Internal support functions
>>   ***********************************************************************/
>>
>> -static inline bool is_hamming_ecc(struct brcmnand_cfg *cfg)
>> +static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
>> +                               struct brcmnand_cfg *cfg)
>>  {
>> -     return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
>> -             cfg->ecc_level == 15;
>> +     if (ctrl->nand_version <= 0x0701)
>> +             return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
>> +                     cfg->ecc_level == 15;
>> +     else
>> +             return cfg->sector_size_1k == 0 && ((cfg->spare_area_size == 16 &&
>> +                     cfg->ecc_level == 15) ||
>> +                     (cfg->spare_area_size == 28 && cfg->ecc_level == 16));
>>  }
>>
>>  /*
>> @@ -931,7 +988,7 @@ static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
>>       if (p->sector_size_1k)
>>               ecc_level <<= 1;
>>
>> -     if (is_hamming_ecc(p)) {
>> +     if (is_hamming_ecc(host->ctrl, p)) {
>>               ecc->bytes = 3 * sectors;
>>               mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
>>               return 0;
>> @@ -1857,7 +1914,8 @@ static int brcmnand_set_cfg(struct brcmnand_host *host,
>>       return 0;
>>  }
>>
>> -static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
>> +static void brcmnand_print_cfg(struct brcmnand_host *host,
>> +                            char *buf, struct brcmnand_cfg *cfg)
>>  {
>>       buf += sprintf(buf,
>>               "%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
>> @@ -1868,7 +1926,7 @@ static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
>>               cfg->spare_area_size, cfg->device_width);
>>
>>       /* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
>> -     if (is_hamming_ecc(cfg))
>> +     if (is_hamming_ecc(host->ctrl, cfg))
>>               sprintf(buf, ", Hamming ECC");
>>       else if (cfg->sector_size_1k)
>>               sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
>> @@ -1987,7 +2045,7 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
>>
>>       brcmnand_set_ecc_enabled(host, 1);
>>
>> -     brcmnand_print_cfg(msg, cfg);
>> +     brcmnand_print_cfg(host, msg, cfg);
>>       dev_info(ctrl->dev, "detected %s\n", msg);
>>
>>       /* Configure ACC_CONTROL */
>> @@ -1995,6 +2053,10 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
>>       tmp = nand_readreg(ctrl, offs);
>>       tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
>>       tmp &= ~ACC_CONTROL_RD_ERASED;
>> +
>> +     /* We need to turn on Read from erased paged protected by ECC */
>> +     if (ctrl->nand_version >= 0x0702)
>> +             tmp |= ACC_CONTROL_RD_ERASED;
>>       tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
>>       if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
>>               /*
>> @@ -2195,6 +2257,7 @@ static const struct of_device_id brcmnand_of_match[] = {
>>       { .compatible = "brcm,brcmnand-v6.2" },
>>       { .compatible = "brcm,brcmnand-v7.0" },
>>       { .compatible = "brcm,brcmnand-v7.1" },
>> +     { .compatible = "brcm,brcmnand-v7.2" },
>>       {},
>>  };
>>  MODULE_DEVICE_TABLE(of, brcmnand_of_match);
>
>
>
> --
> Boris Brezillon, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rob Herring June 3, 2016, 1:47 a.m. UTC | #3
On Tue, May 31, 2016 at 10:23:02AM -0700, Florian Fainelli wrote:
> The 7.2 controller differs in a few area compared to its predecssor (7.1):
> 
> - NAND scrambler, which we are not using just yet
> - higher ECC levels (up to 120 bits) per 1KB data blocks, also not supported yet
> - up to 128B OOB
> 
> This patchs adds the ncessary code to support such a controller

s/patchs/patch/
s/ncessary/necessary/

> generation and updates the Device Tree binding.
> 
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
> Changes in v2:
> 
> - fixed a bunch of conditionals on the versions which should
>   have been exclusive (spotted by Thomas)
> 
>  .../devicetree/bindings/mtd/brcm,brcmnand.txt      |  1 +

With those changes,

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/mtd/nand/brcmnand/brcmnand.c               | 91 ++++++++++++++++++----
>  2 files changed, 78 insertions(+), 14 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Boris Brezillon June 3, 2016, 10:05 a.m. UTC | #4
On Tue, 31 May 2016 10:23:02 -0700
Florian Fainelli <f.fainelli@gmail.com> wrote:

> The 7.2 controller differs in a few area compared to its predecssor (7.1):
> 
> - NAND scrambler, which we are not using just yet
> - higher ECC levels (up to 120 bits) per 1KB data blocks, also not supported yet
> - up to 128B OOB
> 
> This patchs adds the ncessary code to support such a controller
> generation and updates the Device Tree binding.
> 
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>

Applied with Rob's fixes.

Thanks,

Boris

> ---
> Changes in v2:
> 
> - fixed a bunch of conditionals on the versions which should
>   have been exclusive (spotted by Thomas)
> 
>  .../devicetree/bindings/mtd/brcm,brcmnand.txt      |  1 +
>  drivers/mtd/nand/brcmnand/brcmnand.c               | 91 ++++++++++++++++++----
>  2 files changed, 78 insertions(+), 14 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
> index deb24cbdda82..c8d71e75cb09 100644
> --- a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
> +++ b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
> @@ -27,6 +27,7 @@ Required properties:
>                           brcm,brcmnand-v6.2
>                           brcm,brcmnand-v7.0
>                           brcm,brcmnand-v7.1
> +                         brcm,brcmnand-v7.2
>                           brcm,brcmnand
>  - reg              : the register start and length for NAND register region.
>                       (optional) Flash DMA register range (if present)
> diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
> index b76ad7c0144f..0a54a0f5a4b1 100644
> --- a/drivers/mtd/nand/brcmnand/brcmnand.c
> +++ b/drivers/mtd/nand/brcmnand/brcmnand.c
> @@ -340,6 +340,36 @@ static const u16 brcmnand_regs_v71[] = {
>  	[BRCMNAND_FC_BASE]		= 0x400,
>  };
>  
> +/* BRCMNAND v7.2 */
> +static const u16 brcmnand_regs_v72[] = {
> +	[BRCMNAND_CMD_START]		=  0x04,
> +	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
> +	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
> +	[BRCMNAND_INTFC_STATUS]		=  0x14,
> +	[BRCMNAND_CS_SELECT]		=  0x18,
> +	[BRCMNAND_CS_XOR]		=  0x1c,
> +	[BRCMNAND_LL_OP]		=  0x20,
> +	[BRCMNAND_CS0_BASE]		=  0x50,
> +	[BRCMNAND_CS1_BASE]		=     0,
> +	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
> +	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
> +	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
> +	[BRCMNAND_CORR_COUNT]		= 0x100,
> +	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
> +	[BRCMNAND_CORR_ADDR]		= 0x110,
> +	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
> +	[BRCMNAND_UNCORR_ADDR]		= 0x118,
> +	[BRCMNAND_SEMAPHORE]		= 0x150,
> +	[BRCMNAND_ID]			= 0x194,
> +	[BRCMNAND_ID_EXT]		= 0x198,
> +	[BRCMNAND_LL_RDATA]		= 0x19c,
> +	[BRCMNAND_OOB_READ_BASE]	= 0x200,
> +	[BRCMNAND_OOB_READ_10_BASE]	=     0,
> +	[BRCMNAND_OOB_WRITE_BASE]	= 0x400,
> +	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
> +	[BRCMNAND_FC_BASE]		= 0x600,
> +};
> +
>  enum brcmnand_cs_reg {
>  	BRCMNAND_CS_CFG_EXT = 0,
>  	BRCMNAND_CS_CFG,
> @@ -435,7 +465,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
>  	}
>  
>  	/* Register offsets */
> -	if (ctrl->nand_version >= 0x0701)
> +	if (ctrl->nand_version >= 0x0702)
> +		ctrl->reg_offsets = brcmnand_regs_v72;
> +	else if (ctrl->nand_version >= 0x0701)
>  		ctrl->reg_offsets = brcmnand_regs_v71;
>  	else if (ctrl->nand_version >= 0x0600)
>  		ctrl->reg_offsets = brcmnand_regs_v60;
> @@ -480,7 +512,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
>  	}
>  
>  	/* Maximum spare area sector size (per 512B) */
> -	if (ctrl->nand_version >= 0x0600)
> +	if (ctrl->nand_version >= 0x0702)
> +		ctrl->max_oob = 128;
> +	else if (ctrl->nand_version >= 0x0600)
>  		ctrl->max_oob = 64;
>  	else if (ctrl->nand_version >= 0x0500)
>  		ctrl->max_oob = 32;
> @@ -583,14 +617,20 @@ static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
>  	enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
>  	int cs = host->cs;
>  
> -	if (ctrl->nand_version >= 0x0600)
> +	if (ctrl->nand_version >= 0x0702)
> +		bits = 7;
> +	else if (ctrl->nand_version >= 0x0600)
>  		bits = 6;
>  	else if (ctrl->nand_version >= 0x0500)
>  		bits = 5;
>  	else
>  		bits = 4;
>  
> -	if (ctrl->nand_version >= 0x0600) {
> +	if (ctrl->nand_version >= 0x0702) {
> +		if (cs >= 4)
> +			reg = BRCMNAND_CORR_THRESHOLD_EXT;
> +		shift = (cs % 4) * bits;
> +	} else if (ctrl->nand_version >= 0x0600) {
>  		if (cs >= 5)
>  			reg = BRCMNAND_CORR_THRESHOLD_EXT;
>  		shift = (cs % 5) * bits;
> @@ -631,19 +671,28 @@ enum {
>  
>  static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
>  {
> -	if (ctrl->nand_version >= 0x0600)
> +	if (ctrl->nand_version >= 0x0702)
> +		return GENMASK(7, 0);
> +	else if (ctrl->nand_version >= 0x0600)
>  		return GENMASK(6, 0);
>  	else
>  		return GENMASK(5, 0);
>  }
>  
>  #define NAND_ACC_CONTROL_ECC_SHIFT	16
> +#define NAND_ACC_CONTROL_ECC_EXT_SHIFT	13
>  
>  static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
>  {
>  	u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
>  
> -	return mask << NAND_ACC_CONTROL_ECC_SHIFT;
> +	mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
> +
> +	/* v7.2 includes additional ECC levels */
> +	if (ctrl->nand_version >= 0x0702)
> +		mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
> +
> +	return mask;
>  }
>  
>  static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
> @@ -667,7 +716,9 @@ static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
>  
>  static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
>  {
> -	if (ctrl->nand_version >= 0x0600)
> +	if (ctrl->nand_version >= 0x0702)
> +		return 9;
> +	else if (ctrl->nand_version >= 0x0600)
>  		return 7;
>  	else if (ctrl->nand_version >= 0x0500)
>  		return 6;
> @@ -773,10 +824,16 @@ enum brcmnand_llop_type {
>   * Internal support functions
>   ***********************************************************************/
>  
> -static inline bool is_hamming_ecc(struct brcmnand_cfg *cfg)
> +static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
> +				  struct brcmnand_cfg *cfg)
>  {
> -	return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
> -		cfg->ecc_level == 15;
> +	if (ctrl->nand_version <= 0x0701)
> +		return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
> +			cfg->ecc_level == 15;
> +	else
> +		return cfg->sector_size_1k == 0 && ((cfg->spare_area_size == 16 &&
> +			cfg->ecc_level == 15) ||
> +			(cfg->spare_area_size == 28 && cfg->ecc_level == 16));
>  }
>  
>  /*
> @@ -931,7 +988,7 @@ static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
>  	if (p->sector_size_1k)
>  		ecc_level <<= 1;
>  
> -	if (is_hamming_ecc(p)) {
> +	if (is_hamming_ecc(host->ctrl, p)) {
>  		ecc->bytes = 3 * sectors;
>  		mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
>  		return 0;
> @@ -1857,7 +1914,8 @@ static int brcmnand_set_cfg(struct brcmnand_host *host,
>  	return 0;
>  }
>  
> -static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
> +static void brcmnand_print_cfg(struct brcmnand_host *host,
> +			       char *buf, struct brcmnand_cfg *cfg)
>  {
>  	buf += sprintf(buf,
>  		"%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
> @@ -1868,7 +1926,7 @@ static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
>  		cfg->spare_area_size, cfg->device_width);
>  
>  	/* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
> -	if (is_hamming_ecc(cfg))
> +	if (is_hamming_ecc(host->ctrl, cfg))
>  		sprintf(buf, ", Hamming ECC");
>  	else if (cfg->sector_size_1k)
>  		sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
> @@ -1987,7 +2045,7 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
>  
>  	brcmnand_set_ecc_enabled(host, 1);
>  
> -	brcmnand_print_cfg(msg, cfg);
> +	brcmnand_print_cfg(host, msg, cfg);
>  	dev_info(ctrl->dev, "detected %s\n", msg);
>  
>  	/* Configure ACC_CONTROL */
> @@ -1995,6 +2053,10 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
>  	tmp = nand_readreg(ctrl, offs);
>  	tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
>  	tmp &= ~ACC_CONTROL_RD_ERASED;
> +
> +	/* We need to turn on Read from erased paged protected by ECC */
> +	if (ctrl->nand_version >= 0x0702)
> +		tmp |= ACC_CONTROL_RD_ERASED;
>  	tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
>  	if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
>  		/*
> @@ -2195,6 +2257,7 @@ static const struct of_device_id brcmnand_of_match[] = {
>  	{ .compatible = "brcm,brcmnand-v6.2" },
>  	{ .compatible = "brcm,brcmnand-v7.0" },
>  	{ .compatible = "brcm,brcmnand-v7.1" },
> +	{ .compatible = "brcm,brcmnand-v7.2" },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, brcmnand_of_match);
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
index deb24cbdda82..c8d71e75cb09 100644
--- a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
+++ b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
@@ -27,6 +27,7 @@  Required properties:
                          brcm,brcmnand-v6.2
                          brcm,brcmnand-v7.0
                          brcm,brcmnand-v7.1
+                         brcm,brcmnand-v7.2
                          brcm,brcmnand
 - reg              : the register start and length for NAND register region.
                      (optional) Flash DMA register range (if present)
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index b76ad7c0144f..0a54a0f5a4b1 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -340,6 +340,36 @@  static const u16 brcmnand_regs_v71[] = {
 	[BRCMNAND_FC_BASE]		= 0x400,
 };
 
+/* BRCMNAND v7.2 */
+static const u16 brcmnand_regs_v72[] = {
+	[BRCMNAND_CMD_START]		=  0x04,
+	[BRCMNAND_CMD_EXT_ADDRESS]	=  0x08,
+	[BRCMNAND_CMD_ADDRESS]		=  0x0c,
+	[BRCMNAND_INTFC_STATUS]		=  0x14,
+	[BRCMNAND_CS_SELECT]		=  0x18,
+	[BRCMNAND_CS_XOR]		=  0x1c,
+	[BRCMNAND_LL_OP]		=  0x20,
+	[BRCMNAND_CS0_BASE]		=  0x50,
+	[BRCMNAND_CS1_BASE]		=     0,
+	[BRCMNAND_CORR_THRESHOLD]	=  0xdc,
+	[BRCMNAND_CORR_THRESHOLD_EXT]	=  0xe0,
+	[BRCMNAND_UNCORR_COUNT]		=  0xfc,
+	[BRCMNAND_CORR_COUNT]		= 0x100,
+	[BRCMNAND_CORR_EXT_ADDR]	= 0x10c,
+	[BRCMNAND_CORR_ADDR]		= 0x110,
+	[BRCMNAND_UNCORR_EXT_ADDR]	= 0x114,
+	[BRCMNAND_UNCORR_ADDR]		= 0x118,
+	[BRCMNAND_SEMAPHORE]		= 0x150,
+	[BRCMNAND_ID]			= 0x194,
+	[BRCMNAND_ID_EXT]		= 0x198,
+	[BRCMNAND_LL_RDATA]		= 0x19c,
+	[BRCMNAND_OOB_READ_BASE]	= 0x200,
+	[BRCMNAND_OOB_READ_10_BASE]	=     0,
+	[BRCMNAND_OOB_WRITE_BASE]	= 0x400,
+	[BRCMNAND_OOB_WRITE_10_BASE]	=     0,
+	[BRCMNAND_FC_BASE]		= 0x600,
+};
+
 enum brcmnand_cs_reg {
 	BRCMNAND_CS_CFG_EXT = 0,
 	BRCMNAND_CS_CFG,
@@ -435,7 +465,9 @@  static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
 	}
 
 	/* Register offsets */
-	if (ctrl->nand_version >= 0x0701)
+	if (ctrl->nand_version >= 0x0702)
+		ctrl->reg_offsets = brcmnand_regs_v72;
+	else if (ctrl->nand_version >= 0x0701)
 		ctrl->reg_offsets = brcmnand_regs_v71;
 	else if (ctrl->nand_version >= 0x0600)
 		ctrl->reg_offsets = brcmnand_regs_v60;
@@ -480,7 +512,9 @@  static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
 	}
 
 	/* Maximum spare area sector size (per 512B) */
-	if (ctrl->nand_version >= 0x0600)
+	if (ctrl->nand_version >= 0x0702)
+		ctrl->max_oob = 128;
+	else if (ctrl->nand_version >= 0x0600)
 		ctrl->max_oob = 64;
 	else if (ctrl->nand_version >= 0x0500)
 		ctrl->max_oob = 32;
@@ -583,14 +617,20 @@  static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
 	enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
 	int cs = host->cs;
 
-	if (ctrl->nand_version >= 0x0600)
+	if (ctrl->nand_version >= 0x0702)
+		bits = 7;
+	else if (ctrl->nand_version >= 0x0600)
 		bits = 6;
 	else if (ctrl->nand_version >= 0x0500)
 		bits = 5;
 	else
 		bits = 4;
 
-	if (ctrl->nand_version >= 0x0600) {
+	if (ctrl->nand_version >= 0x0702) {
+		if (cs >= 4)
+			reg = BRCMNAND_CORR_THRESHOLD_EXT;
+		shift = (cs % 4) * bits;
+	} else if (ctrl->nand_version >= 0x0600) {
 		if (cs >= 5)
 			reg = BRCMNAND_CORR_THRESHOLD_EXT;
 		shift = (cs % 5) * bits;
@@ -631,19 +671,28 @@  enum {
 
 static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
 {
-	if (ctrl->nand_version >= 0x0600)
+	if (ctrl->nand_version >= 0x0702)
+		return GENMASK(7, 0);
+	else if (ctrl->nand_version >= 0x0600)
 		return GENMASK(6, 0);
 	else
 		return GENMASK(5, 0);
 }
 
 #define NAND_ACC_CONTROL_ECC_SHIFT	16
+#define NAND_ACC_CONTROL_ECC_EXT_SHIFT	13
 
 static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
 {
 	u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
 
-	return mask << NAND_ACC_CONTROL_ECC_SHIFT;
+	mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
+
+	/* v7.2 includes additional ECC levels */
+	if (ctrl->nand_version >= 0x0702)
+		mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
+
+	return mask;
 }
 
 static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
@@ -667,7 +716,9 @@  static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
 
 static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
 {
-	if (ctrl->nand_version >= 0x0600)
+	if (ctrl->nand_version >= 0x0702)
+		return 9;
+	else if (ctrl->nand_version >= 0x0600)
 		return 7;
 	else if (ctrl->nand_version >= 0x0500)
 		return 6;
@@ -773,10 +824,16 @@  enum brcmnand_llop_type {
  * Internal support functions
  ***********************************************************************/
 
-static inline bool is_hamming_ecc(struct brcmnand_cfg *cfg)
+static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
+				  struct brcmnand_cfg *cfg)
 {
-	return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
-		cfg->ecc_level == 15;
+	if (ctrl->nand_version <= 0x0701)
+		return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
+			cfg->ecc_level == 15;
+	else
+		return cfg->sector_size_1k == 0 && ((cfg->spare_area_size == 16 &&
+			cfg->ecc_level == 15) ||
+			(cfg->spare_area_size == 28 && cfg->ecc_level == 16));
 }
 
 /*
@@ -931,7 +988,7 @@  static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
 	if (p->sector_size_1k)
 		ecc_level <<= 1;
 
-	if (is_hamming_ecc(p)) {
+	if (is_hamming_ecc(host->ctrl, p)) {
 		ecc->bytes = 3 * sectors;
 		mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
 		return 0;
@@ -1857,7 +1914,8 @@  static int brcmnand_set_cfg(struct brcmnand_host *host,
 	return 0;
 }
 
-static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
+static void brcmnand_print_cfg(struct brcmnand_host *host,
+			       char *buf, struct brcmnand_cfg *cfg)
 {
 	buf += sprintf(buf,
 		"%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
@@ -1868,7 +1926,7 @@  static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
 		cfg->spare_area_size, cfg->device_width);
 
 	/* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
-	if (is_hamming_ecc(cfg))
+	if (is_hamming_ecc(host->ctrl, cfg))
 		sprintf(buf, ", Hamming ECC");
 	else if (cfg->sector_size_1k)
 		sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
@@ -1987,7 +2045,7 @@  static int brcmnand_setup_dev(struct brcmnand_host *host)
 
 	brcmnand_set_ecc_enabled(host, 1);
 
-	brcmnand_print_cfg(msg, cfg);
+	brcmnand_print_cfg(host, msg, cfg);
 	dev_info(ctrl->dev, "detected %s\n", msg);
 
 	/* Configure ACC_CONTROL */
@@ -1995,6 +2053,10 @@  static int brcmnand_setup_dev(struct brcmnand_host *host)
 	tmp = nand_readreg(ctrl, offs);
 	tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
 	tmp &= ~ACC_CONTROL_RD_ERASED;
+
+	/* We need to turn on Read from erased paged protected by ECC */
+	if (ctrl->nand_version >= 0x0702)
+		tmp |= ACC_CONTROL_RD_ERASED;
 	tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
 	if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
 		/*
@@ -2195,6 +2257,7 @@  static const struct of_device_id brcmnand_of_match[] = {
 	{ .compatible = "brcm,brcmnand-v6.2" },
 	{ .compatible = "brcm,brcmnand-v7.0" },
 	{ .compatible = "brcm,brcmnand-v7.1" },
+	{ .compatible = "brcm,brcmnand-v7.2" },
 	{},
 };
 MODULE_DEVICE_TABLE(of, brcmnand_of_match);