rk27xx: read each run of NAND sectors with one page latch

flash_read() latched the page afresh for every sector. The controller
streams a page from its first sector, so each sector also cost a
transfer of every sector before it in the page: reading an 8-sector
page sector by sector took 8 array loads and 36 sector transfers
instead of 1 and 8. Over USB mass storage on a Samsung YP-CP3 the
NAND read at 1.87 MB/s, against 8.25 MB/s in the original firmware.

Read each run of sectors that lie consecutively in one raw page with a
single latch. On a two-plane part a run of FTL sectors stays in one
page until it moves on to the other plane.

On the YP-CP3, same test: 5.64 MB/s, every read verified.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I9b08e56f4429ae432ccd2d2e23b9b34c18e56e97
This commit is contained in:
Marcin Bukat 2026-10-01 21:00:02 +02:00
parent 17db971b66
commit 7e9d621f29

View file

@ -331,11 +331,18 @@ int flash_read(uint32_t sec, void *data, void *meta, unsigned n)
unsigned i;
int ret = ready ? 0 : 1;
/* One page latch per sector. Reading whole runs in one pass is an
* obvious speed-up, left until the access pattern has been measured. */
for (i = 0; i < n && ready; i++)
unsigned run;
/* One page latch per run of sectors that lie consecutively in one raw
* page. Latching per sector instead cost an array load per sector and,
* the controller streaming a page from its first sector, a transfer of
* every sector before it: 8 loads and 36 transfers for an 8-sector page
* read sector by sector, against 1 and 8. On a two-plane part a run of
* FTL sectors stays in one page until it moves on to the other plane. */
for (i = 0; i < n && ready; i += run)
{
uint32_t raw = sec_to_raw(sec + i);
uint32_t slot = raw % geo.sec_per_page_raw;
if (raw >= geo.total_sectors)
{
@ -343,8 +350,14 @@ int flash_read(uint32_t sec, void *data, void *meta, unsigned n)
break;
}
if (read_raw_run(raw / geo.sec_per_page_raw,
raw % geo.sec_per_page_raw, 1,
run = 1;
while (i + run < n && slot + run < geo.sec_per_page_raw &&
sec_to_raw(sec + i + run) == raw + run)
{
run++;
}
if (read_raw_run(raw / geo.sec_per_page_raw, slot, run,
d ? d + (size_t)i * FLASH_SECTOR_SIZE : NULL,
m ? m + (size_t)i * FLASH_META_SIZE : NULL, ecc_mode))
{