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