rk27xx: build the raw NAND layer

nand-rk27xx.c held a complete transcription of the OF's NAND handling -
chip detection, geometry derivation, chip select, ECC reads - inside
"#if 0", written as documentation back when the FTL was still unknown.
It has therefore never been compiled.

Enabling it exposed three things nothing had ever caught:

 - flash_init() looks up ManufactureIDTbl[] and DeviceCode[], but the
   tables are named manufacture_id_tbl[] and device_code[]
 - mlc_refresh_row, flash_pend_cmd and flash_read_status_cmd are
   assigned but were never defined
 - memcpy() was used without including string.h

struct flashspec_t moves to nand-target.h, with flash_spec[] and
total_phy_sec declared there, because the FTL's flash primitives need
the geometry flash_init() derives. The "_raw" fields describe one
physical plane and the others the multi-plane view the FTL addresses;
that distinction is load-bearing for the FTL's address mapping, so both
are kept.

flash_read_page() is renamed flash_read_page_raw(). It reads a whole
page unbuffered and without ECC, and the name is needed for the FTL
primitive that does the ECC read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I3eb2d6f41d72b3239a0f9493e49532c242c588fa
This commit is contained in:
Marcin Bukat 2026-09-23 19:03:19 +02:00
parent 53bc6abc97
commit c3356ac35f
2 changed files with 82 additions and 35 deletions

View file

@ -19,46 +19,28 @@
****************************************************************************/
#include "config.h"
#include "system.h"
#include "string.h"
#include "nand-target.h"
#include "rk27xx.h"
#if 0
/* This is for documentation purpose as FTL has not been reverse engineered yet
* Raw nand handling functions based on OF disassembly and partially inspired
* by Rockchip patent
/* Raw nand handling functions based on OF disassembly and partially inspired
* by Rockchip patent.
*
* This was written as documentation while the FTL was still unknown and sat
* under `#if 0` for years. The Scheme A FTL is now reconstructed
* (ftl-scheme-a.c) and needs exactly what this provides: chip detection and
* the geometry derived from it, plus chip select. Enabled.
*/
#define MAX_FLASH_NUM 4
/* MAX_FLASH_NUM now in nand-target.h */
#define CMD_READ_STATUS 0x70
#define CMD_RESET 0xFF
#define CMD_READ_ID 0x90
#define READ_PAGE_CMD 0x30
/* this is the struct OF uses */
struct flashspec_t
{
uint8_t cache_prog;
uint8_t mul_plane;
uint8_t interleave;
uint8_t large;
uint8_t five;
uint8_t mlc;
uint8_t vendor;
uint8_t access_time;
uint8_t sec_per_page;
uint8_t sec_per_page_raw;
uint16_t sec_per_block;
uint16_t sec_per_block_raw;
uint16_t page_per_block;
uint16_t page_per_block_raw;
uint32_t tot_logic_sec;
uint32_t total_phy_sec;
uint32_t total_bloks;
uint32_t cmd;
uint32_t addr;
uint32_t data;
};
/* struct flashspec_t now lives in nand-target.h - the Scheme A FTL's flash
* primitives (flash-rk27xx.c) need the geometry flash_init() derives here. */
/* holds nand chips characteristics */
struct flashspec_t flash_spec[MAX_FLASH_NUM];
@ -111,6 +93,31 @@ const uint32_t device_info[] =
0x800000 /* 4G, large page */
};
/* State the OF keeps across flash operations.
*
* These were referenced by flash_init() but never transcribed - the block was
* under `#if 0`, so nothing caught it. They are defined here with the values
* flash_init() assigns, which is all the current code needs:
*
* - mlc_refresh_row: row scheduled for refresh after a sector needed
* BCH_REFRESH_THRESHOLD corrected bits; 0xffffffff means "none pending".
* - flash_pend_cmd: the OF defers a program command so it can be merged with
* the next one (cache programming). Nothing issues one yet.
* - flash_read_status_cmd: READ STATUS opcode, which differs on some
* multi-plane parts.
*/
uint32_t mlc_refresh_row;
struct flash_pend_cmd_t
{
uint8_t valid;
uint32_t row;
};
struct flash_pend_cmd_t flash_pend_cmd;
uint8_t flash_read_status_cmd;
static int flash_delay(int n)
{
volatile int cnt, i, j;
@ -196,7 +203,7 @@ void flash_init(void)
for (j=0; j<sizeof(manufacture_id_tbl); j++)
{
/* store Manufacturer index */
if (ManufactureIDTbl[j] == buff[0])
if (manufacture_id_tbl[j] == buff[0])
{
flash_spec[i].vendor = j;
}
@ -207,7 +214,7 @@ void flash_init(void)
/* look for matching device code
* and store total phys sectors
*/
if (DeviceCode[j] == buff[1])
if (device_code[j] == buff[1])
{
flash_spec[i].total_phy_sec = device_info[j];
break;
@ -309,7 +316,7 @@ void flash_init(void)
}
/* read single page in unbuffered mode */
void flash_read_page(int page, unsigned char *pgbuff)
void flash_read_page_raw(int page, unsigned char *pgbuff)
{
unsigned int i;
@ -414,7 +421,6 @@ void flash_read_sector(int page, unsigned char *secbuf, int nsec)
flash_chip_deselect();
}
#endif
const struct nand_device_info_type* nand_get_device_type(uint32_t bank);

View file

@ -24,6 +24,47 @@
#include "config.h"
#include "inttypes.h"
#define MAX_FLASH_NUM 4
/* Per-chip geometry, as the OF derives it from the READ_ID response.
*
* The "_raw" fields describe one physical plane; the others are the
* multi-plane view the FTL addresses (sec_per_page = sec_per_page_raw *
* mul_plane, and likewise for blocks). The Scheme A FTL's address mapping
* depends on exactly this distinction, so both are kept. Populated by
* flash_init(). */
struct flashspec_t
{
uint8_t cache_prog;
uint8_t mul_plane;
uint8_t interleave;
uint8_t large;
uint8_t five;
uint8_t mlc;
uint8_t vendor;
uint8_t access_time;
uint8_t sec_per_page;
uint8_t sec_per_page_raw;
uint16_t sec_per_block;
uint16_t sec_per_block_raw;
uint16_t page_per_block;
uint16_t page_per_block_raw;
uint32_t tot_logic_sec;
uint32_t total_phy_sec;
uint32_t total_bloks;
uint32_t cmd;
uint32_t addr;
uint32_t data;
};
extern struct flashspec_t flash_spec[MAX_FLASH_NUM];
extern uint32_t total_phy_sec;
void flash_init(void);
void flash_chip_select(uint8_t chip);
void flash_chip_deselect(void);
struct nand_device_info_type
{