Message ID | 1369226342-20102-1-git-send-email-zajec5@gmail.com |
---|---|
State | Accepted |
Commit | 13134f48c8a7a9daaef74118d19f2d2ef29cd33a |
Headers | show |
2013/5/22 Rafał Miłecki <zajec5@gmail.com>: > --- > drivers/mtd/devices/bcm47xxsflash.c | 130 +++++++++++++++++++++++++++++++++-- > 1 file changed, 126 insertions(+), 4 deletions(-) To make it clear, it was successfully tested with BCM4706.
Hi Rafal, On Wed, May 22, 2013 at 02:39:02PM +0200, Rafał Miłecki wrote: > --- > drivers/mtd/devices/bcm47xxsflash.c | 130 +++++++++++++++++++++++++++++++++-- > 1 file changed, 126 insertions(+), 4 deletions(-) Can I get a 'Signed-off-by'? Otherwise, is this patch good to go? > > diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c > index c485d96..effe624 100644 > --- a/drivers/mtd/devices/bcm47xxsflash.c > +++ b/drivers/mtd/devices/bcm47xxsflash.c > @@ -116,6 +116,127 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, > return len; > } > > +static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len, > + const u_char *buf) > +{ > + struct bcm47xxsflash *b47s = mtd->priv; > + int written = 0; > + > + /* Enable writes */ > + bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN); > + > + /* Write first byte */ > + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset); > + b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++); > + > + /* Program page */ > + if (b47s->bcma_cc->core->id.rev < 20) { > + bcm47xxsflash_cmd(b47s, OPCODE_ST_PP); > + return 1; /* 1B written */ > + } > + > + /* Program page and set CSA (on newer chips we can continue writing) */ > + bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP); > + offset++; > + len--; > + written++; > + > + while (len > 0) { > + /* Page boundary, another function call is needed */ > + if ((offset & 0xFF) == 0) > + break; > + > + bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++); > + offset++; > + len--; > + written++; > + } > + > + /* All done, drop CSA & poll */ > + b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0); > + udelay(1); > + if (bcm47xxsflash_poll(b47s, HZ / 10)) > + pr_err("Flash rejected dropping CSA\n"); > + > + return written; > +} > + > +static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len, > + const u_char *buf) > +{ > + struct bcm47xxsflash *b47s = mtd->priv; > + u32 mask = b47s->blocksize - 1; > + u32 page = (offset & ~mask) << 1; > + u32 byte = offset & mask; > + int written = 0; > + > + /* If we don't overwrite whole page, read it to the buffer first */ > + if (byte || (len < b47s->blocksize)) { > + int err; > + > + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page); > + bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD); > + /* 250 us for AT45DB321B */ > + err = bcm47xxsflash_poll(b47s, HZ / 1000); > + if (err) { > + pr_err("Timeout reading page 0x%X info buffer\n", page); > + return err; > + } > + } > + > + /* Change buffer content with our data */ > + while (len > 0) { > + /* Page boundary, another function call is needed */ > + if (byte == b47s->blocksize) > + break; > + > + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++); > + b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++); > + bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE); > + len--; > + written++; > + } > + > + /* Program page with the buffer content */ > + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page); > + bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM); > + > + return written; > +} > + > +static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len, > + size_t *retlen, const u_char *buf) > +{ > + struct bcm47xxsflash *b47s = mtd->priv; > + int written; > + > + /* Writing functions can return without writing all passed data, for > + * example when the hardware is too old or when we git page boundary. > + */ > + while (len > 0) { > + switch (b47s->type) { > + case BCM47XXSFLASH_TYPE_ST: > + written = bcm47xxsflash_write_st(mtd, to, len, buf); > + break; > + case BCM47XXSFLASH_TYPE_ATMEL: > + written = bcm47xxsflash_write_at(mtd, to, len, buf); > + break; > + default: > + BUG_ON(1); > + } > + if (written < 0) { > + pr_err("Error writing at offset 0x%llX\n", to); > + return written; > + } > + to += (loff_t)written; > + len -= written; > + *retlen += written; > + buf += written; > + } > + > + return 0; > +} > + > static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) > { > struct mtd_info *mtd = &b47s->mtd; > @@ -123,16 +244,17 @@ static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) > mtd->priv = b47s; > mtd->name = "bcm47xxsflash"; > mtd->owner = THIS_MODULE; > - mtd->type = MTD_ROM; > > - /* TODO: implement writing support and verify/change following code */ > - mtd->flags = MTD_CAP_ROM; > + mtd->type = MTD_NORFLASH; > + mtd->flags = MTD_CAP_NORFLASH; > mtd->size = b47s->size; > mtd->erasesize = b47s->blocksize; > - mtd->writebufsize = mtd->writesize = 1; > + mtd->writesize = 1; > + mtd->writebufsize = 1; > > mtd->_erase = bcm47xxsflash_erase; > mtd->_read = bcm47xxsflash_read; > + mtd->_write = bcm47xxsflash_write; > } > > /************************************************** Brian
2013/8/22 Brian Norris <computersforpeace@gmail.com>: > Hi Rafal, > > On Wed, May 22, 2013 at 02:39:02PM +0200, Rafał Miłecki wrote: >> --- >> drivers/mtd/devices/bcm47xxsflash.c | 130 +++++++++++++++++++++++++++++++++-- >> 1 file changed, 126 insertions(+), 4 deletions(-) > > Can I get a 'Signed-off-by'? Otherwise, is this patch good to go? Of course! I posted it as RFC, so didn't add S-o-b, but no-one objected and this patch seems to be fine. I use it daily for half a year, it was recently picked up by OpenWrt and I didn't get any bug reports. So I think it's totally fine to push it :) Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
On Thu, Aug 22, 2013 at 10:03:22PM +0200, Rafał Miłecki wrote: > 2013/8/22 Brian Norris <computersforpeace@gmail.com>: > > Hi Rafal, > > > > On Wed, May 22, 2013 at 02:39:02PM +0200, Rafał Miłecki wrote: > >> --- > >> drivers/mtd/devices/bcm47xxsflash.c | 130 +++++++++++++++++++++++++++++++++-- > >> 1 file changed, 126 insertions(+), 4 deletions(-) > > > > Can I get a 'Signed-off-by'? Otherwise, is this patch good to go? > > Of course! I posted it as RFC, so didn't add S-o-b, but no-one > objected and this patch seems to be fine. I use it daily for half a > year, it was recently picked up by OpenWrt and I didn't get any bug > reports. So I think it's totally fine to push it :) > > Signed-off-by: Rafał Miłecki <zajec5@gmail.com> Applied to l2-mtd.git. Brian
diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c index c485d96..effe624 100644 --- a/drivers/mtd/devices/bcm47xxsflash.c +++ b/drivers/mtd/devices/bcm47xxsflash.c @@ -116,6 +116,127 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, return len; } +static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len, + const u_char *buf) +{ + struct bcm47xxsflash *b47s = mtd->priv; + int written = 0; + + /* Enable writes */ + bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN); + + /* Write first byte */ + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset); + b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++); + + /* Program page */ + if (b47s->bcma_cc->core->id.rev < 20) { + bcm47xxsflash_cmd(b47s, OPCODE_ST_PP); + return 1; /* 1B written */ + } + + /* Program page and set CSA (on newer chips we can continue writing) */ + bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP); + offset++; + len--; + written++; + + while (len > 0) { + /* Page boundary, another function call is needed */ + if ((offset & 0xFF) == 0) + break; + + bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++); + offset++; + len--; + written++; + } + + /* All done, drop CSA & poll */ + b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0); + udelay(1); + if (bcm47xxsflash_poll(b47s, HZ / 10)) + pr_err("Flash rejected dropping CSA\n"); + + return written; +} + +static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len, + const u_char *buf) +{ + struct bcm47xxsflash *b47s = mtd->priv; + u32 mask = b47s->blocksize - 1; + u32 page = (offset & ~mask) << 1; + u32 byte = offset & mask; + int written = 0; + + /* If we don't overwrite whole page, read it to the buffer first */ + if (byte || (len < b47s->blocksize)) { + int err; + + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page); + bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD); + /* 250 us for AT45DB321B */ + err = bcm47xxsflash_poll(b47s, HZ / 1000); + if (err) { + pr_err("Timeout reading page 0x%X info buffer\n", page); + return err; + } + } + + /* Change buffer content with our data */ + while (len > 0) { + /* Page boundary, another function call is needed */ + if (byte == b47s->blocksize) + break; + + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++); + b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++); + bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE); + len--; + written++; + } + + /* Program page with the buffer content */ + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page); + bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM); + + return written; +} + +static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct bcm47xxsflash *b47s = mtd->priv; + int written; + + /* Writing functions can return without writing all passed data, for + * example when the hardware is too old or when we git page boundary. + */ + while (len > 0) { + switch (b47s->type) { + case BCM47XXSFLASH_TYPE_ST: + written = bcm47xxsflash_write_st(mtd, to, len, buf); + break; + case BCM47XXSFLASH_TYPE_ATMEL: + written = bcm47xxsflash_write_at(mtd, to, len, buf); + break; + default: + BUG_ON(1); + } + if (written < 0) { + pr_err("Error writing at offset 0x%llX\n", to); + return written; + } + to += (loff_t)written; + len -= written; + *retlen += written; + buf += written; + } + + return 0; +} + static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) { struct mtd_info *mtd = &b47s->mtd; @@ -123,16 +244,17 @@ static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s) mtd->priv = b47s; mtd->name = "bcm47xxsflash"; mtd->owner = THIS_MODULE; - mtd->type = MTD_ROM; - /* TODO: implement writing support and verify/change following code */ - mtd->flags = MTD_CAP_ROM; + mtd->type = MTD_NORFLASH; + mtd->flags = MTD_CAP_NORFLASH; mtd->size = b47s->size; mtd->erasesize = b47s->blocksize; - mtd->writebufsize = mtd->writesize = 1; + mtd->writesize = 1; + mtd->writebufsize = 1; mtd->_erase = bcm47xxsflash_erase; mtd->_read = bcm47xxsflash_read; + mtd->_write = bcm47xxsflash_write; } /**************************************************