Message ID | 20170116220916.2603-1-zajec5@gmail.com |
---|---|
State | Superseded |
Headers | show |
On 01/16/2017 11:09 PM, Rafał Miłecki wrote: > From: Rafał Miłecki <rafal@milecki.pl> > > For reading flash content we use MMIO but it's possible to read only > first 16 MiB this way. It's simply an arch design/limitation. > To support flash sizes bigger than 16 MiB implement indirect access > using ChipCommon registers. > This has been tested using MX25L25635F. > > Signed-off-by: Rafał Miłecki <rafal@milecki.pl> > --- > drivers/mtd/devices/bcm47xxsflash.c | 12 +++++++++++- > drivers/mtd/devices/bcm47xxsflash.h | 3 +++ > 2 files changed, 14 insertions(+), 1 deletion(-) > > diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c > index 4decd8c..5d57119 100644 > --- a/drivers/mtd/devices/bcm47xxsflash.c > +++ b/drivers/mtd/devices/bcm47xxsflash.c > @@ -110,7 +110,17 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, > if ((from + len) > mtd->size) > return -EINVAL; > > - memcpy_fromio(buf, b47s->window + from, len); > + if (from + len <= BCM47XXSFLASH_WINDOW_SIZE) { > + memcpy_fromio(buf, b47s->window + from, len); > + } else { > + size_t i; > + > + for (i = 0; i < len; i++) { > + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++); > + bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B); > + *(buf++) = b47s->cc_read(b47s, BCMA_CC_FLASHDATA) & 0xff; Do you really need to send command on every write into the FLASHADDR register ? Doesn't this hardware support some sort of seqeuntial reading? Are you sure this has no side-effects when you mix this with reading from the flash window ? Also, the parenthesis around buf++ are not needed and the & 0xff should not be needed either. > + } > + } > *retlen = len; > > return len; > diff --git a/drivers/mtd/devices/bcm47xxsflash.h b/drivers/mtd/devices/bcm47xxsflash.h > index 1564b62..d8d1093 100644 > --- a/drivers/mtd/devices/bcm47xxsflash.h > +++ b/drivers/mtd/devices/bcm47xxsflash.h > @@ -3,6 +3,8 @@ > > #include <linux/mtd/mtd.h> > > +#define BCM47XXSFLASH_WINDOW_SIZE SZ_16M > + > /* Used for ST flashes only. */ > #define OPCODE_ST_WREN 0x0006 /* Write Enable */ > #define OPCODE_ST_WRDIS 0x0004 /* Write Disable */ These look like standard opcodes, why don't you use standard opcodes in this driver and instead redefine them here ? > @@ -16,6 +18,7 @@ > #define OPCODE_ST_RES 0x03ab /* Read Electronic Signature */ > #define OPCODE_ST_CSA 0x1000 /* Keep chip select asserted */ > #define OPCODE_ST_SSE 0x0220 /* Sub-sector Erase */ > +#define OPCODE_ST_READ4B 0x6313 Needs a comment to keep this consistent I think. > /* Used for Atmel flashes only. */ > #define OPCODE_AT_READ 0x07e8 >
On 17 January 2017 at 04:18, Marek Vasut <marek.vasut@gmail.com> wrote: > On 01/16/2017 11:09 PM, Rafał Miłecki wrote: >> From: Rafał Miłecki <rafal@milecki.pl> >> >> For reading flash content we use MMIO but it's possible to read only >> first 16 MiB this way. It's simply an arch design/limitation. >> To support flash sizes bigger than 16 MiB implement indirect access >> using ChipCommon registers. >> This has been tested using MX25L25635F. >> >> Signed-off-by: Rafał Miłecki <rafal@milecki.pl> >> --- >> drivers/mtd/devices/bcm47xxsflash.c | 12 +++++++++++- >> drivers/mtd/devices/bcm47xxsflash.h | 3 +++ >> 2 files changed, 14 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c >> index 4decd8c..5d57119 100644 >> --- a/drivers/mtd/devices/bcm47xxsflash.c >> +++ b/drivers/mtd/devices/bcm47xxsflash.c >> @@ -110,7 +110,17 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, >> if ((from + len) > mtd->size) >> return -EINVAL; >> >> - memcpy_fromio(buf, b47s->window + from, len); >> + if (from + len <= BCM47XXSFLASH_WINDOW_SIZE) { >> + memcpy_fromio(buf, b47s->window + from, len); >> + } else { >> + size_t i; >> + >> + for (i = 0; i < len; i++) { >> + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++); >> + bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B); >> + *(buf++) = b47s->cc_read(b47s, BCMA_CC_FLASHDATA) & 0xff; > > Do you really need to send command on every write into the FLASHADDR > register ? Doesn't this hardware support some sort of seqeuntial reading? Yes, I need to. If there is some other way it's undocumented and not used by Broadcom. As a quick check I tried not writing to FLASHADDR every time, but it didn't work. > Are you sure this has no side-effects when you mix this with reading > from the flash window ? No side effects. I also tried reading whole flash content using this indirect access and it worked as well. > Also, the parenthesis around buf++ are not needed and the & 0xff should > not be needed either. You're right about buf. I'm not sure about & 0xff though. In theory you're correct. This is 32b register and we use 32b read function to access it but I never saw anything set in 0xffffff00. On the other hand Broadcom /advises/ (does) this & 0xff so I'm wondering if there can be some hardware with unexpected behavior in the world? What would happen if we got 32b value with some bits in ~0xff? >> + } >> + } >> *retlen = len; >> >> return len; >> diff --git a/drivers/mtd/devices/bcm47xxsflash.h b/drivers/mtd/devices/bcm47xxsflash.h >> index 1564b62..d8d1093 100644 >> --- a/drivers/mtd/devices/bcm47xxsflash.h >> +++ b/drivers/mtd/devices/bcm47xxsflash.h >> @@ -3,6 +3,8 @@ >> >> #include <linux/mtd/mtd.h> >> >> +#define BCM47XXSFLASH_WINDOW_SIZE SZ_16M >> + >> /* Used for ST flashes only. */ >> #define OPCODE_ST_WREN 0x0006 /* Write Enable */ >> #define OPCODE_ST_WRDIS 0x0004 /* Write Disable */ > > These look like standard opcodes, why don't you use standard opcodes in > this driver and instead redefine them here ? I guess it's because these are the only 2 opcodes we could share. Other than them Broadcom uses their magic 16b opcodes so I guess it doesn't change that much since we need most of them defined locally anyway. >> @@ -16,6 +18,7 @@ >> #define OPCODE_ST_RES 0x03ab /* Read Electronic Signature */ >> #define OPCODE_ST_CSA 0x1000 /* Keep chip select asserted */ >> #define OPCODE_ST_SSE 0x0220 /* Sub-sector Erase */ >> +#define OPCODE_ST_READ4B 0x6313 > > Needs a comment to keep this consistent I think. OK
On 01/17/2017 07:58 AM, Rafał Miłecki wrote: > On 17 January 2017 at 04:18, Marek Vasut <marek.vasut@gmail.com> wrote: >> On 01/16/2017 11:09 PM, Rafał Miłecki wrote: >>> From: Rafał Miłecki <rafal@milecki.pl> >>> >>> For reading flash content we use MMIO but it's possible to read only >>> first 16 MiB this way. It's simply an arch design/limitation. >>> To support flash sizes bigger than 16 MiB implement indirect access >>> using ChipCommon registers. >>> This has been tested using MX25L25635F. >>> >>> Signed-off-by: Rafał Miłecki <rafal@milecki.pl> >>> --- >>> drivers/mtd/devices/bcm47xxsflash.c | 12 +++++++++++- >>> drivers/mtd/devices/bcm47xxsflash.h | 3 +++ >>> 2 files changed, 14 insertions(+), 1 deletion(-) >>> >>> diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c >>> index 4decd8c..5d57119 100644 >>> --- a/drivers/mtd/devices/bcm47xxsflash.c >>> +++ b/drivers/mtd/devices/bcm47xxsflash.c >>> @@ -110,7 +110,17 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, >>> if ((from + len) > mtd->size) >>> return -EINVAL; >>> >>> - memcpy_fromio(buf, b47s->window + from, len); >>> + if (from + len <= BCM47XXSFLASH_WINDOW_SIZE) { >>> + memcpy_fromio(buf, b47s->window + from, len); >>> + } else { >>> + size_t i; >>> + >>> + for (i = 0; i < len; i++) { >>> + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++); >>> + bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B); >>> + *(buf++) = b47s->cc_read(b47s, BCMA_CC_FLASHDATA) & 0xff; >> >> Do you really need to send command on every write into the FLASHADDR >> register ? Doesn't this hardware support some sort of seqeuntial reading? > > Yes, I need to. If there is some other way it's undocumented and not > used by Broadcom. As a quick check I tried not writing to FLASHADDR > every time, but it didn't work. Oh well, that's a bit sad. Thanks for checking. >> Are you sure this has no side-effects when you mix this with reading >> from the flash window ? > > No side effects. I also tried reading whole flash content using this > indirect access and it worked as well. Well, if you read the whole flash, you will trigger the first windowed read and then the new code, in sequence. Try doing some read pattern where you read from the beginning and mix it with reads from the end. That will alternate between these two bits of code. >> Also, the parenthesis around buf++ are not needed and the & 0xff should >> not be needed either. > > You're right about buf. I'm not sure about & 0xff though. In theory > you're correct. This is 32b register and we use 32b read function to > access it but I never saw anything set in 0xffffff00. On the other > hand Broadcom /advises/ (does) this & 0xff so I'm wondering if there > can be some hardware with unexpected behavior in the world? What would > happen if we got 32b value with some bits in ~0xff? Well you're storing unsigned 32bit to unsigned 8bit, right ? >>> + } >>> + } >>> *retlen = len; >>> >>> return len; >>> diff --git a/drivers/mtd/devices/bcm47xxsflash.h b/drivers/mtd/devices/bcm47xxsflash.h >>> index 1564b62..d8d1093 100644 >>> --- a/drivers/mtd/devices/bcm47xxsflash.h >>> +++ b/drivers/mtd/devices/bcm47xxsflash.h >>> @@ -3,6 +3,8 @@ >>> >>> #include <linux/mtd/mtd.h> >>> >>> +#define BCM47XXSFLASH_WINDOW_SIZE SZ_16M >>> + >>> /* Used for ST flashes only. */ >>> #define OPCODE_ST_WREN 0x0006 /* Write Enable */ >>> #define OPCODE_ST_WRDIS 0x0004 /* Write Disable */ >> >> These look like standard opcodes, why don't you use standard opcodes in >> this driver and instead redefine them here ? > > I guess it's because these are the only 2 opcodes we could share. > Other than them Broadcom uses their magic 16b opcodes so I guess it > doesn't change that much since we need most of them defined locally > anyway. I see. >>> @@ -16,6 +18,7 @@ >>> #define OPCODE_ST_RES 0x03ab /* Read Electronic Signature */ >>> #define OPCODE_ST_CSA 0x1000 /* Keep chip select asserted */ >>> #define OPCODE_ST_SSE 0x0220 /* Sub-sector Erase */ >>> +#define OPCODE_ST_READ4B 0x6313 >> >> Needs a comment to keep this consistent I think. > > OK >
On 17 January 2017 at 10:49, Marek Vasut <marek.vasut@gmail.com> wrote: > On 01/17/2017 07:58 AM, Rafał Miłecki wrote: >> On 17 January 2017 at 04:18, Marek Vasut <marek.vasut@gmail.com> wrote: >>> On 01/16/2017 11:09 PM, Rafał Miłecki wrote: >>>> From: Rafał Miłecki <rafal@milecki.pl> >>>> >>>> For reading flash content we use MMIO but it's possible to read only >>>> first 16 MiB this way. It's simply an arch design/limitation. >>>> To support flash sizes bigger than 16 MiB implement indirect access >>>> using ChipCommon registers. >>>> This has been tested using MX25L25635F. >>>> >>>> Signed-off-by: Rafał Miłecki <rafal@milecki.pl> >>>> --- >>>> drivers/mtd/devices/bcm47xxsflash.c | 12 +++++++++++- >>>> drivers/mtd/devices/bcm47xxsflash.h | 3 +++ >>>> 2 files changed, 14 insertions(+), 1 deletion(-) >>>> >>>> diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c >>>> index 4decd8c..5d57119 100644 >>>> --- a/drivers/mtd/devices/bcm47xxsflash.c >>>> +++ b/drivers/mtd/devices/bcm47xxsflash.c >>>> @@ -110,7 +110,17 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, >>>> if ((from + len) > mtd->size) >>>> return -EINVAL; >>>> >>>> - memcpy_fromio(buf, b47s->window + from, len); >>>> + if (from + len <= BCM47XXSFLASH_WINDOW_SIZE) { >>>> + memcpy_fromio(buf, b47s->window + from, len); >>>> + } else { >>>> + size_t i; >>>> + >>>> + for (i = 0; i < len; i++) { >>>> + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++); >>>> + bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B); >>>> + *(buf++) = b47s->cc_read(b47s, BCMA_CC_FLASHDATA) & 0xff; >>> >>> Do you really need to send command on every write into the FLASHADDR >>> register ? Doesn't this hardware support some sort of seqeuntial reading? >> >> Yes, I need to. If there is some other way it's undocumented and not >> used by Broadcom. As a quick check I tried not writing to FLASHADDR >> every time, but it didn't work. > > Oh well, that's a bit sad. Thanks for checking. > >>> Are you sure this has no side-effects when you mix this with reading >>> from the flash window ? >> >> No side effects. I also tried reading whole flash content using this >> indirect access and it worked as well. > > Well, if you read the whole flash, you will trigger the first windowed > read and then the new code, in sequence. Try doing some read pattern > where you read from the beginning and mix it with reads from the end. > That will alternate between these two bits of code. I really can't follow your possible-fail scenario. With my patch first 16 MiB are read using windowed access, another 16 MiB using indirect access. I scanned whole flash this way, it worked. I got a working system. It just works...
On 01/17/2017 11:39 AM, Rafał Miłecki wrote: > On 17 January 2017 at 10:49, Marek Vasut <marek.vasut@gmail.com> wrote: >> On 01/17/2017 07:58 AM, Rafał Miłecki wrote: >>> On 17 January 2017 at 04:18, Marek Vasut <marek.vasut@gmail.com> wrote: >>>> On 01/16/2017 11:09 PM, Rafał Miłecki wrote: >>>>> From: Rafał Miłecki <rafal@milecki.pl> >>>>> >>>>> For reading flash content we use MMIO but it's possible to read only >>>>> first 16 MiB this way. It's simply an arch design/limitation. >>>>> To support flash sizes bigger than 16 MiB implement indirect access >>>>> using ChipCommon registers. >>>>> This has been tested using MX25L25635F. >>>>> >>>>> Signed-off-by: Rafał Miłecki <rafal@milecki.pl> >>>>> --- >>>>> drivers/mtd/devices/bcm47xxsflash.c | 12 +++++++++++- >>>>> drivers/mtd/devices/bcm47xxsflash.h | 3 +++ >>>>> 2 files changed, 14 insertions(+), 1 deletion(-) >>>>> >>>>> diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c >>>>> index 4decd8c..5d57119 100644 >>>>> --- a/drivers/mtd/devices/bcm47xxsflash.c >>>>> +++ b/drivers/mtd/devices/bcm47xxsflash.c >>>>> @@ -110,7 +110,17 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, >>>>> if ((from + len) > mtd->size) >>>>> return -EINVAL; >>>>> >>>>> - memcpy_fromio(buf, b47s->window + from, len); >>>>> + if (from + len <= BCM47XXSFLASH_WINDOW_SIZE) { >>>>> + memcpy_fromio(buf, b47s->window + from, len); >>>>> + } else { >>>>> + size_t i; >>>>> + >>>>> + for (i = 0; i < len; i++) { >>>>> + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++); >>>>> + bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B); >>>>> + *(buf++) = b47s->cc_read(b47s, BCMA_CC_FLASHDATA) & 0xff; >>>> >>>> Do you really need to send command on every write into the FLASHADDR >>>> register ? Doesn't this hardware support some sort of seqeuntial reading? >>> >>> Yes, I need to. If there is some other way it's undocumented and not >>> used by Broadcom. As a quick check I tried not writing to FLASHADDR >>> every time, but it didn't work. >> >> Oh well, that's a bit sad. Thanks for checking. >> >>>> Are you sure this has no side-effects when you mix this with reading >>>> from the flash window ? >>> >>> No side effects. I also tried reading whole flash content using this >>> indirect access and it worked as well. >> >> Well, if you read the whole flash, you will trigger the first windowed >> read and then the new code, in sequence. Try doing some read pattern >> where you read from the beginning and mix it with reads from the end. >> That will alternate between these two bits of code. > > I really can't follow your possible-fail scenario. With my patch first > 16 MiB are read using windowed access, another 16 MiB using indirect > access. I scanned whole flash this way, it worked. I got a working > system. It just works... > Well if you scanned the whole flash, you triggered the memcpy_fromio() first and then the b47s->cc_write(..) stuff , in that order. So does it work if you read the first 16 MiB after you read the region past 16 MiB?
On 17 January 2017 at 11:49, Marek Vasut <marek.vasut@gmail.com> wrote: > On 01/17/2017 11:39 AM, Rafał Miłecki wrote: >> On 17 January 2017 at 10:49, Marek Vasut <marek.vasut@gmail.com> wrote: >>> On 01/17/2017 07:58 AM, Rafał Miłecki wrote: >>>> On 17 January 2017 at 04:18, Marek Vasut <marek.vasut@gmail.com> wrote: >>>>> On 01/16/2017 11:09 PM, Rafał Miłecki wrote: >>>>>> From: Rafał Miłecki <rafal@milecki.pl> >>>>>> >>>>>> For reading flash content we use MMIO but it's possible to read only >>>>>> first 16 MiB this way. It's simply an arch design/limitation. >>>>>> To support flash sizes bigger than 16 MiB implement indirect access >>>>>> using ChipCommon registers. >>>>>> This has been tested using MX25L25635F. >>>>>> >>>>>> Signed-off-by: Rafał Miłecki <rafal@milecki.pl> >>>>>> --- >>>>>> drivers/mtd/devices/bcm47xxsflash.c | 12 +++++++++++- >>>>>> drivers/mtd/devices/bcm47xxsflash.h | 3 +++ >>>>>> 2 files changed, 14 insertions(+), 1 deletion(-) >>>>>> >>>>>> diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c >>>>>> index 4decd8c..5d57119 100644 >>>>>> --- a/drivers/mtd/devices/bcm47xxsflash.c >>>>>> +++ b/drivers/mtd/devices/bcm47xxsflash.c >>>>>> @@ -110,7 +110,17 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, >>>>>> if ((from + len) > mtd->size) >>>>>> return -EINVAL; >>>>>> >>>>>> - memcpy_fromio(buf, b47s->window + from, len); >>>>>> + if (from + len <= BCM47XXSFLASH_WINDOW_SIZE) { >>>>>> + memcpy_fromio(buf, b47s->window + from, len); >>>>>> + } else { >>>>>> + size_t i; >>>>>> + >>>>>> + for (i = 0; i < len; i++) { >>>>>> + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++); >>>>>> + bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B); >>>>>> + *(buf++) = b47s->cc_read(b47s, BCMA_CC_FLASHDATA) & 0xff; >>>>> >>>>> Do you really need to send command on every write into the FLASHADDR >>>>> register ? Doesn't this hardware support some sort of seqeuntial reading? >>>> >>>> Yes, I need to. If there is some other way it's undocumented and not >>>> used by Broadcom. As a quick check I tried not writing to FLASHADDR >>>> every time, but it didn't work. >>> >>> Oh well, that's a bit sad. Thanks for checking. >>> >>>>> Are you sure this has no side-effects when you mix this with reading >>>>> from the flash window ? >>>> >>>> No side effects. I also tried reading whole flash content using this >>>> indirect access and it worked as well. >>> >>> Well, if you read the whole flash, you will trigger the first windowed >>> read and then the new code, in sequence. Try doing some read pattern >>> where you read from the beginning and mix it with reads from the end. >>> That will alternate between these two bits of code. >> >> I really can't follow your possible-fail scenario. With my patch first >> 16 MiB are read using windowed access, another 16 MiB using indirect >> access. I scanned whole flash this way, it worked. I got a working >> system. It just works... >> > Well if you scanned the whole flash, you triggered the memcpy_fromio() > first and then the b47s->cc_write(..) stuff , in that order. So does it > work if you read the first 16 MiB after you read the region past 16 MiB? Yes, of course it does.
On 01/17/2017 11:50 AM, Rafał Miłecki wrote: > On 17 January 2017 at 11:49, Marek Vasut <marek.vasut@gmail.com> wrote: >> On 01/17/2017 11:39 AM, Rafał Miłecki wrote: >>> On 17 January 2017 at 10:49, Marek Vasut <marek.vasut@gmail.com> wrote: >>>> On 01/17/2017 07:58 AM, Rafał Miłecki wrote: >>>>> On 17 January 2017 at 04:18, Marek Vasut <marek.vasut@gmail.com> wrote: >>>>>> On 01/16/2017 11:09 PM, Rafał Miłecki wrote: >>>>>>> From: Rafał Miłecki <rafal@milecki.pl> >>>>>>> >>>>>>> For reading flash content we use MMIO but it's possible to read only >>>>>>> first 16 MiB this way. It's simply an arch design/limitation. >>>>>>> To support flash sizes bigger than 16 MiB implement indirect access >>>>>>> using ChipCommon registers. >>>>>>> This has been tested using MX25L25635F. >>>>>>> >>>>>>> Signed-off-by: Rafał Miłecki <rafal@milecki.pl> >>>>>>> --- >>>>>>> drivers/mtd/devices/bcm47xxsflash.c | 12 +++++++++++- >>>>>>> drivers/mtd/devices/bcm47xxsflash.h | 3 +++ >>>>>>> 2 files changed, 14 insertions(+), 1 deletion(-) >>>>>>> >>>>>>> diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c >>>>>>> index 4decd8c..5d57119 100644 >>>>>>> --- a/drivers/mtd/devices/bcm47xxsflash.c >>>>>>> +++ b/drivers/mtd/devices/bcm47xxsflash.c >>>>>>> @@ -110,7 +110,17 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, >>>>>>> if ((from + len) > mtd->size) >>>>>>> return -EINVAL; >>>>>>> >>>>>>> - memcpy_fromio(buf, b47s->window + from, len); >>>>>>> + if (from + len <= BCM47XXSFLASH_WINDOW_SIZE) { >>>>>>> + memcpy_fromio(buf, b47s->window + from, len); >>>>>>> + } else { >>>>>>> + size_t i; >>>>>>> + >>>>>>> + for (i = 0; i < len; i++) { >>>>>>> + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++); >>>>>>> + bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B); >>>>>>> + *(buf++) = b47s->cc_read(b47s, BCMA_CC_FLASHDATA) & 0xff; >>>>>> >>>>>> Do you really need to send command on every write into the FLASHADDR >>>>>> register ? Doesn't this hardware support some sort of seqeuntial reading? >>>>> >>>>> Yes, I need to. If there is some other way it's undocumented and not >>>>> used by Broadcom. As a quick check I tried not writing to FLASHADDR >>>>> every time, but it didn't work. >>>> >>>> Oh well, that's a bit sad. Thanks for checking. >>>> >>>>>> Are you sure this has no side-effects when you mix this with reading >>>>>> from the flash window ? >>>>> >>>>> No side effects. I also tried reading whole flash content using this >>>>> indirect access and it worked as well. >>>> >>>> Well, if you read the whole flash, you will trigger the first windowed >>>> read and then the new code, in sequence. Try doing some read pattern >>>> where you read from the beginning and mix it with reads from the end. >>>> That will alternate between these two bits of code. >>> >>> I really can't follow your possible-fail scenario. With my patch first >>> 16 MiB are read using windowed access, another 16 MiB using indirect >>> access. I scanned whole flash this way, it worked. I got a working >>> system. It just works... >>> >> Well if you scanned the whole flash, you triggered the memcpy_fromio() >> first and then the b47s->cc_write(..) stuff , in that order. So does it >> work if you read the first 16 MiB after you read the region past 16 MiB? > > Yes, of course it does. Ah cool, thanks for checking.
diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c index 4decd8c..5d57119 100644 --- a/drivers/mtd/devices/bcm47xxsflash.c +++ b/drivers/mtd/devices/bcm47xxsflash.c @@ -110,7 +110,17 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, if ((from + len) > mtd->size) return -EINVAL; - memcpy_fromio(buf, b47s->window + from, len); + if (from + len <= BCM47XXSFLASH_WINDOW_SIZE) { + memcpy_fromio(buf, b47s->window + from, len); + } else { + size_t i; + + for (i = 0; i < len; i++) { + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++); + bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B); + *(buf++) = b47s->cc_read(b47s, BCMA_CC_FLASHDATA) & 0xff; + } + } *retlen = len; return len; diff --git a/drivers/mtd/devices/bcm47xxsflash.h b/drivers/mtd/devices/bcm47xxsflash.h index 1564b62..d8d1093 100644 --- a/drivers/mtd/devices/bcm47xxsflash.h +++ b/drivers/mtd/devices/bcm47xxsflash.h @@ -3,6 +3,8 @@ #include <linux/mtd/mtd.h> +#define BCM47XXSFLASH_WINDOW_SIZE SZ_16M + /* Used for ST flashes only. */ #define OPCODE_ST_WREN 0x0006 /* Write Enable */ #define OPCODE_ST_WRDIS 0x0004 /* Write Disable */ @@ -16,6 +18,7 @@ #define OPCODE_ST_RES 0x03ab /* Read Electronic Signature */ #define OPCODE_ST_CSA 0x1000 /* Keep chip select asserted */ #define OPCODE_ST_SSE 0x0220 /* Sub-sector Erase */ +#define OPCODE_ST_READ4B 0x6313 /* Used for Atmel flashes only. */ #define OPCODE_AT_READ 0x07e8