Skip to content

Commit 13134f4

Browse files
rmileckiDavid Woodhouse
authored andcommitted
mtd: bcm47xxsflash: writing support
Tested with BCM4706. Signed-off-by: Rafał Miłecki <zajec5@gmail.com> Signed-off-by: Brian Norris <computersforpeace@gmail.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
1 parent c0fcbc5 commit 13134f4

File tree

1 file changed

+126
-4
lines changed

1 file changed

+126
-4
lines changed

drivers/mtd/devices/bcm47xxsflash.c

Lines changed: 126 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,23 +116,145 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
116116
return len;
117117
}
118118

119+
static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len,
120+
const u_char *buf)
121+
{
122+
struct bcm47xxsflash *b47s = mtd->priv;
123+
int written = 0;
124+
125+
/* Enable writes */
126+
bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
127+
128+
/* Write first byte */
129+
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset);
130+
b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
131+
132+
/* Program page */
133+
if (b47s->bcma_cc->core->id.rev < 20) {
134+
bcm47xxsflash_cmd(b47s, OPCODE_ST_PP);
135+
return 1; /* 1B written */
136+
}
137+
138+
/* Program page and set CSA (on newer chips we can continue writing) */
139+
bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP);
140+
offset++;
141+
len--;
142+
written++;
143+
144+
while (len > 0) {
145+
/* Page boundary, another function call is needed */
146+
if ((offset & 0xFF) == 0)
147+
break;
148+
149+
bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++);
150+
offset++;
151+
len--;
152+
written++;
153+
}
154+
155+
/* All done, drop CSA & poll */
156+
b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0);
157+
udelay(1);
158+
if (bcm47xxsflash_poll(b47s, HZ / 10))
159+
pr_err("Flash rejected dropping CSA\n");
160+
161+
return written;
162+
}
163+
164+
static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len,
165+
const u_char *buf)
166+
{
167+
struct bcm47xxsflash *b47s = mtd->priv;
168+
u32 mask = b47s->blocksize - 1;
169+
u32 page = (offset & ~mask) << 1;
170+
u32 byte = offset & mask;
171+
int written = 0;
172+
173+
/* If we don't overwrite whole page, read it to the buffer first */
174+
if (byte || (len < b47s->blocksize)) {
175+
int err;
176+
177+
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
178+
bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD);
179+
/* 250 us for AT45DB321B */
180+
err = bcm47xxsflash_poll(b47s, HZ / 1000);
181+
if (err) {
182+
pr_err("Timeout reading page 0x%X info buffer\n", page);
183+
return err;
184+
}
185+
}
186+
187+
/* Change buffer content with our data */
188+
while (len > 0) {
189+
/* Page boundary, another function call is needed */
190+
if (byte == b47s->blocksize)
191+
break;
192+
193+
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++);
194+
b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
195+
bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE);
196+
len--;
197+
written++;
198+
}
199+
200+
/* Program page with the buffer content */
201+
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
202+
bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM);
203+
204+
return written;
205+
}
206+
207+
static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len,
208+
size_t *retlen, const u_char *buf)
209+
{
210+
struct bcm47xxsflash *b47s = mtd->priv;
211+
int written;
212+
213+
/* Writing functions can return without writing all passed data, for
214+
* example when the hardware is too old or when we git page boundary.
215+
*/
216+
while (len > 0) {
217+
switch (b47s->type) {
218+
case BCM47XXSFLASH_TYPE_ST:
219+
written = bcm47xxsflash_write_st(mtd, to, len, buf);
220+
break;
221+
case BCM47XXSFLASH_TYPE_ATMEL:
222+
written = bcm47xxsflash_write_at(mtd, to, len, buf);
223+
break;
224+
default:
225+
BUG_ON(1);
226+
}
227+
if (written < 0) {
228+
pr_err("Error writing at offset 0x%llX\n", to);
229+
return written;
230+
}
231+
to += (loff_t)written;
232+
len -= written;
233+
*retlen += written;
234+
buf += written;
235+
}
236+
237+
return 0;
238+
}
239+
119240
static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
120241
{
121242
struct mtd_info *mtd = &b47s->mtd;
122243

123244
mtd->priv = b47s;
124245
mtd->name = "bcm47xxsflash";
125246
mtd->owner = THIS_MODULE;
126-
mtd->type = MTD_ROM;
127247

128-
/* TODO: implement writing support and verify/change following code */
129-
mtd->flags = MTD_CAP_ROM;
248+
mtd->type = MTD_NORFLASH;
249+
mtd->flags = MTD_CAP_NORFLASH;
130250
mtd->size = b47s->size;
131251
mtd->erasesize = b47s->blocksize;
132-
mtd->writebufsize = mtd->writesize = 1;
252+
mtd->writesize = 1;
253+
mtd->writebufsize = 1;
133254

134255
mtd->_erase = bcm47xxsflash_erase;
135256
mtd->_read = bcm47xxsflash_read;
257+
mtd->_write = bcm47xxsflash_write;
136258
}
137259

138260
/**************************************************

0 commit comments

Comments
 (0)