rk27xx: make the BCH strength of the FTL area selectable

The controller has a second ECC mode, BCHCTL bit 13: t=14 instead of
t=8, over the same field and polynomial. Some firmware writes its FTL
area in it - the Archos Vision 28 does - while every boot area seen is
t=8.

flash_set_ecc() selects the mode for reads and copies of the FTL area;
flash_read_raw(), which reads the boot area, stays at t=8. Writing is
refused in t=14 mode: a t=14 sector is a 538-byte record on the media
(3 metadata and 23 parity bytes), the program path addresses 528-byte
records, and programming in that mode has not been tried.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Iaf4ce9274b72838b7719232fc49cdce0cceecbac
This commit is contained in:
Marcin Bukat 2026-10-01 09:28:08 +02:00
parent 6bf3eaff41
commit efde59472e
2 changed files with 45 additions and 10 deletions

View file

@ -77,6 +77,7 @@ static struct flash_geometry geo;
static bool ready;
static bool writable;
static bool meta_passthrough;
static uint32_t ecc_mode; /* BCHCTL mode bits: 0 or BCH_T14 */
static uint32_t boot_area = UINT32_MAX;
static struct flash_stats stats;
@ -135,6 +136,25 @@ void flash_set_meta_passthrough(bool on)
meta_passthrough = on;
}
int flash_set_ecc(unsigned t)
{
int ret = 0;
if (t == 8)
{
ecc_mode = 0;
}
else if (t == 14)
{
ecc_mode = BCH_T14;
}
else
{
ret = 1;
}
return ret;
}
void flash_get_stats(struct flash_stats *out)
{
*out = stats;
@ -208,8 +228,9 @@ static void send_row(uint32_t row)
FLASH_ADDR(0) = (row >> 16) & 0xff;
}
/* Latch raw page `row` in the chip and prepare the ECC engine to decode. */
static void latch_page(uint32_t row)
/* Latch raw page `row` in the chip and prepare the ECC engine to decode in
* `mode` (BCHCTL mode bits). */
static void latch_page(uint32_t row, uint32_t mode)
{
flash_chip_select(0);
wait_flash_ready();
@ -222,8 +243,7 @@ static void latch_page(uint32_t row)
wait_flash_ready();
/* ECC on, t=8 - right for the whole chip on the devices seen */
BCHCTL = BCH_RST;
BCHCTL = BCH_RST | mode;
}
/* Transfer the next sector of the latched page through slot `slot` & 3.
@ -256,12 +276,12 @@ static uint32_t read_next_sector(uint32_t slot, uint8_t *data, uint8_t *meta)
/* Read sectors [first, first + n) of raw page `row`. Returns 1 if any was
* uncorrectable. */
static int read_raw_run(uint32_t row, uint32_t first, uint32_t n,
uint8_t *data, uint8_t *meta)
uint8_t *data, uint8_t *meta, uint32_t mode)
{
uint32_t j;
int uncorrectable = 0;
latch_page(row);
latch_page(row, mode);
for (j = 0; j < first + n; j++)
{
@ -296,8 +316,10 @@ int flash_read_raw(uint32_t raw_sec, void *data, void *meta)
if (ready && raw_sec < geo.total_sectors)
{
/* the boot area is t=8 on every device seen, whatever the FTL
* area uses */
ret = read_raw_run(raw_sec / geo.sec_per_page_raw,
raw_sec % geo.sec_per_page_raw, 1, data, meta);
raw_sec % geo.sec_per_page_raw, 1, data, meta, 0);
}
return ret;
}
@ -324,7 +346,7 @@ int flash_read(uint32_t sec, void *data, void *meta, unsigned n)
if (read_raw_run(raw / geo.sec_per_page_raw,
raw % geo.sec_per_page_raw, 1,
d ? d + (size_t)i * FLASH_SECTOR_SIZE : NULL,
m ? m + (size_t)i * FLASH_META_SIZE : NULL))
m ? m + (size_t)i * FLASH_META_SIZE : NULL, ecc_mode))
{
ret = 1;
}
@ -334,9 +356,13 @@ int flash_read(uint32_t sec, void *data, void *meta, unsigned n)
/* ---- writing ---- */
/* A write is refused in t=14 mode too: a t=14 sector is a 538-byte record
* on the media - 512 data, 3 metadata, 23 parity - where the program path
* below addresses 528-byte records, and programming in that mode has not
* been tried. */
static bool write_refused(void)
{
bool refused = !ready || !writable;
bool refused = !ready || !writable || ecc_mode != 0;
if (refused)
{
@ -620,7 +646,8 @@ static int copy_sectors(uint32_t src, uint32_t dst, unsigned n,
if (read_raw_run(raw / geo.sec_per_page_raw, first, run,
buf + (size_t)i * FLASH_SECTOR_SIZE,
how == COPY_META_KEEP ?
meta + (size_t)i * FLASH_META_SIZE : NULL))
meta + (size_t)i * FLASH_META_SIZE : NULL,
ecc_mode))
{
stats.copy_uncorrectable++;
}

View file

@ -112,6 +112,14 @@ int flash_copy_meta(uint32_t src, uint32_t dst, unsigned n,
/* Program metadata byte 1 as given rather than 0x00. */
void flash_set_meta_passthrough(bool on);
/* The BCH strength of the FTL's area: t = 8 (the default) or 14, the
* controller's BCH_T14 mode. flash_read_raw() always reads t=8, as the
* boot area is on every device seen. Writing is refused in t=14 mode: its
* sectors are 538-byte records on the media (3 + 23 spare bytes), and
* programming them has not been tried.
* Returns 0, or 1 for an unsupported t. */
int flash_set_ecc(unsigned t);
/* Read one PHYSICAL sector, bypassing the super-block view: for the boot
* area, which the boot ROM addresses physically. */
int flash_read_raw(uint32_t raw_sec, void *data, void *meta);