| b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From 7e7c7df5d50fe06469be106967fc5b5d62be8868 Mon Sep 17 00:00:00 2001 |
| 2 | From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com> |
| 3 | Date: Fri, 22 May 2020 14:15:24 +0200 |
| 4 | Subject: [PATCH] mtd: rawnand: brcmnand: support v2.1-v2.2 controllers |
| 5 | MIME-Version: 1.0 |
| 6 | Content-Type: text/plain; charset=UTF-8 |
| 7 | Content-Transfer-Encoding: 8bit |
| 8 | |
| 9 | v2.1: tested on Netgear DGND3700v1 (BCM6368) |
| 10 | v2.2: tested on Netgear DGND3700v2 (BCM6362) |
| 11 | |
| 12 | Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com> |
| 13 | Acked-by: Florian Fainelli <f.fainelli@gmail.com> |
| 14 | Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> |
| 15 | Link: https://lore.kernel.org/linux-mtd/20200522121524.4161539-6-noltari@gmail.com |
| 16 | --- |
| 17 | drivers/mtd/nand/raw/brcmnand/brcmnand.c | 85 +++++++++++++++++++++--- |
| 18 | 1 file changed, 76 insertions(+), 9 deletions(-) |
| 19 | |
| 20 | --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c |
| 21 | +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c |
| 22 | @@ -196,6 +196,7 @@ struct brcmnand_controller { |
| 23 | const unsigned int *block_sizes; |
| 24 | unsigned int max_page_size; |
| 25 | const unsigned int *page_sizes; |
| 26 | + unsigned int page_size_shift; |
| 27 | unsigned int max_oob; |
| 28 | u32 features; |
| 29 | |
| 30 | @@ -269,6 +270,36 @@ enum brcmnand_reg { |
| 31 | BRCMNAND_FC_BASE, |
| 32 | }; |
| 33 | |
| 34 | +/* BRCMNAND v2.1-v2.2 */ |
| 35 | +static const u16 brcmnand_regs_v21[] = { |
| 36 | + [BRCMNAND_CMD_START] = 0x04, |
| 37 | + [BRCMNAND_CMD_EXT_ADDRESS] = 0x08, |
| 38 | + [BRCMNAND_CMD_ADDRESS] = 0x0c, |
| 39 | + [BRCMNAND_INTFC_STATUS] = 0x5c, |
| 40 | + [BRCMNAND_CS_SELECT] = 0x14, |
| 41 | + [BRCMNAND_CS_XOR] = 0x18, |
| 42 | + [BRCMNAND_LL_OP] = 0, |
| 43 | + [BRCMNAND_CS0_BASE] = 0x40, |
| 44 | + [BRCMNAND_CS1_BASE] = 0, |
| 45 | + [BRCMNAND_CORR_THRESHOLD] = 0, |
| 46 | + [BRCMNAND_CORR_THRESHOLD_EXT] = 0, |
| 47 | + [BRCMNAND_UNCORR_COUNT] = 0, |
| 48 | + [BRCMNAND_CORR_COUNT] = 0, |
| 49 | + [BRCMNAND_CORR_EXT_ADDR] = 0x60, |
| 50 | + [BRCMNAND_CORR_ADDR] = 0x64, |
| 51 | + [BRCMNAND_UNCORR_EXT_ADDR] = 0x68, |
| 52 | + [BRCMNAND_UNCORR_ADDR] = 0x6c, |
| 53 | + [BRCMNAND_SEMAPHORE] = 0x50, |
| 54 | + [BRCMNAND_ID] = 0x54, |
| 55 | + [BRCMNAND_ID_EXT] = 0, |
| 56 | + [BRCMNAND_LL_RDATA] = 0, |
| 57 | + [BRCMNAND_OOB_READ_BASE] = 0x20, |
| 58 | + [BRCMNAND_OOB_READ_10_BASE] = 0, |
| 59 | + [BRCMNAND_OOB_WRITE_BASE] = 0x30, |
| 60 | + [BRCMNAND_OOB_WRITE_10_BASE] = 0, |
| 61 | + [BRCMNAND_FC_BASE] = 0x200, |
| 62 | +}; |
| 63 | + |
| 64 | /* BRCMNAND v3.3-v4.0 */ |
| 65 | static const u16 brcmnand_regs_v33[] = { |
| 66 | [BRCMNAND_CMD_START] = 0x04, |
| 67 | @@ -467,6 +498,9 @@ enum { |
| 68 | CFG_BUS_WIDTH = BIT(CFG_BUS_WIDTH_SHIFT), |
| 69 | CFG_DEVICE_SIZE_SHIFT = 24, |
| 70 | |
| 71 | + /* Only for v2.1 */ |
| 72 | + CFG_PAGE_SIZE_SHIFT_v2_1 = 30, |
| 73 | + |
| 74 | /* Only for pre-v7.1 (with no CFG_EXT register) */ |
| 75 | CFG_PAGE_SIZE_SHIFT = 20, |
| 76 | CFG_BLK_SIZE_SHIFT = 28, |
| 77 | @@ -502,12 +536,16 @@ static int brcmnand_revision_init(struct |
| 78 | { |
| 79 | static const unsigned int block_sizes_v6[] = { 8, 16, 128, 256, 512, 1024, 2048, 0 }; |
| 80 | static const unsigned int block_sizes_v4[] = { 16, 128, 8, 512, 256, 1024, 2048, 0 }; |
| 81 | + static const unsigned int block_sizes_v2_2[] = { 16, 128, 8, 512, 256, 0 }; |
| 82 | + static const unsigned int block_sizes_v2_1[] = { 16, 128, 8, 512, 0 }; |
| 83 | static const unsigned int page_sizes_v3_4[] = { 512, 2048, 4096, 8192, 0 }; |
| 84 | + static const unsigned int page_sizes_v2_2[] = { 512, 2048, 4096, 0 }; |
| 85 | + static const unsigned int page_sizes_v2_1[] = { 512, 2048, 0 }; |
| 86 | |
| 87 | ctrl->nand_version = nand_readreg(ctrl, 0) & 0xffff; |
| 88 | |
| 89 | - /* Only support v4.0+? */ |
| 90 | - if (ctrl->nand_version < 0x0400) { |
| 91 | + /* Only support v2.1+ */ |
| 92 | + if (ctrl->nand_version < 0x0201) { |
| 93 | dev_err(ctrl->dev, "version %#x not supported\n", |
| 94 | ctrl->nand_version); |
| 95 | return -ENODEV; |
| 96 | @@ -524,6 +562,8 @@ static int brcmnand_revision_init(struct |
| 97 | ctrl->reg_offsets = brcmnand_regs_v50; |
| 98 | else if (ctrl->nand_version >= 0x0303) |
| 99 | ctrl->reg_offsets = brcmnand_regs_v33; |
| 100 | + else if (ctrl->nand_version >= 0x0201) |
| 101 | + ctrl->reg_offsets = brcmnand_regs_v21; |
| 102 | |
| 103 | /* Chip-select stride */ |
| 104 | if (ctrl->nand_version >= 0x0701) |
| 105 | @@ -549,14 +589,32 @@ static int brcmnand_revision_init(struct |
| 106 | ctrl->max_page_size = 16 * 1024; |
| 107 | ctrl->max_block_size = 2 * 1024 * 1024; |
| 108 | } else { |
| 109 | - ctrl->page_sizes = page_sizes_v3_4; |
| 110 | + if (ctrl->nand_version >= 0x0304) |
| 111 | + ctrl->page_sizes = page_sizes_v3_4; |
| 112 | + else if (ctrl->nand_version >= 0x0202) |
| 113 | + ctrl->page_sizes = page_sizes_v2_2; |
| 114 | + else |
| 115 | + ctrl->page_sizes = page_sizes_v2_1; |
| 116 | + |
| 117 | + if (ctrl->nand_version >= 0x0202) |
| 118 | + ctrl->page_size_shift = CFG_PAGE_SIZE_SHIFT; |
| 119 | + else |
| 120 | + ctrl->page_size_shift = CFG_PAGE_SIZE_SHIFT_v2_1; |
| 121 | + |
| 122 | if (ctrl->nand_version >= 0x0600) |
| 123 | ctrl->block_sizes = block_sizes_v6; |
| 124 | - else |
| 125 | + else if (ctrl->nand_version >= 0x0400) |
| 126 | ctrl->block_sizes = block_sizes_v4; |
| 127 | + else if (ctrl->nand_version >= 0x0202) |
| 128 | + ctrl->block_sizes = block_sizes_v2_2; |
| 129 | + else |
| 130 | + ctrl->block_sizes = block_sizes_v2_1; |
| 131 | |
| 132 | if (ctrl->nand_version < 0x0400) { |
| 133 | - ctrl->max_page_size = 4096; |
| 134 | + if (ctrl->nand_version < 0x0202) |
| 135 | + ctrl->max_page_size = 2048; |
| 136 | + else |
| 137 | + ctrl->max_page_size = 4096; |
| 138 | ctrl->max_block_size = 512 * 1024; |
| 139 | } |
| 140 | } |
| 141 | @@ -724,6 +782,9 @@ static void brcmnand_wr_corr_thresh(stru |
| 142 | enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD; |
| 143 | int cs = host->cs; |
| 144 | |
| 145 | + if (!ctrl->reg_offsets[reg]) |
| 146 | + return; |
| 147 | + |
| 148 | if (ctrl->nand_version == 0x0702) |
| 149 | bits = 7; |
| 150 | else if (ctrl->nand_version >= 0x0600) |
| 151 | @@ -782,8 +843,10 @@ static inline u32 brcmnand_spare_area_ma |
| 152 | return GENMASK(7, 0); |
| 153 | else if (ctrl->nand_version >= 0x0600) |
| 154 | return GENMASK(6, 0); |
| 155 | - else |
| 156 | + else if (ctrl->nand_version >= 0x0303) |
| 157 | return GENMASK(5, 0); |
| 158 | + else |
| 159 | + return GENMASK(4, 0); |
| 160 | } |
| 161 | |
| 162 | #define NAND_ACC_CONTROL_ECC_SHIFT 16 |
| 163 | @@ -2146,7 +2209,7 @@ static int brcmnand_set_cfg(struct brcmn |
| 164 | (!!(cfg->device_width == 16) << CFG_BUS_WIDTH_SHIFT) | |
| 165 | (device_size << CFG_DEVICE_SIZE_SHIFT); |
| 166 | if (cfg_offs == cfg_ext_offs) { |
| 167 | - tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) | |
| 168 | + tmp |= (page_size << ctrl->page_size_shift) | |
| 169 | (block_size << CFG_BLK_SIZE_SHIFT); |
| 170 | nand_writereg(ctrl, cfg_offs, tmp); |
| 171 | } else { |
| 172 | @@ -2158,9 +2221,11 @@ static int brcmnand_set_cfg(struct brcmn |
| 173 | |
| 174 | tmp = nand_readreg(ctrl, acc_control_offs); |
| 175 | tmp &= ~brcmnand_ecc_level_mask(ctrl); |
| 176 | - tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT; |
| 177 | tmp &= ~brcmnand_spare_area_mask(ctrl); |
| 178 | - tmp |= cfg->spare_area_size; |
| 179 | + if (ctrl->nand_version >= 0x0302) { |
| 180 | + tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT; |
| 181 | + tmp |= cfg->spare_area_size; |
| 182 | + } |
| 183 | nand_writereg(ctrl, acc_control_offs, tmp); |
| 184 | |
| 185 | brcmnand_set_sector_size_1k(host, cfg->sector_size_1k); |
| 186 | @@ -2530,6 +2595,8 @@ const struct dev_pm_ops brcmnand_pm_ops |
| 187 | EXPORT_SYMBOL_GPL(brcmnand_pm_ops); |
| 188 | |
| 189 | static const struct of_device_id brcmnand_of_match[] = { |
| 190 | + { .compatible = "brcm,brcmnand-v2.1" }, |
| 191 | + { .compatible = "brcm,brcmnand-v2.2" }, |
| 192 | { .compatible = "brcm,brcmnand-v4.0" }, |
| 193 | { .compatible = "brcm,brcmnand-v5.0" }, |
| 194 | { .compatible = "brcm,brcmnand-v6.0" }, |