Полный текст следует Appnote_rk_storage_0001, Rev.08, страницы 4–23. Единственный PDF находится в китайском каталоге, но его основной текст английский. Английская статья сохраняет оригинал; китайская, русская и немецкая полностью переводят его. Все версии используют исходные английские схемы и снимки; отдельного китайского оригинала или PDF из английского каталога нет. Это справочник по платформе ArmSoM, а не подтверждение поддержки всех плат. Источник не задаёт конкретные SoC, плату, SDK/BSP и версию ядра: необходимо проверить накопитель, загрузочную разметку, драйвер, ABI и узел устройства. Аппаратные операции чтения/записи и испытания при отключении питания не выполнялись.
Внимание: последний пример записи заменяет ID 1 (SN) байтами 0–31. Не запускайте его на производственных устройствах; сначала сохраните идентификаторы и данные подготовки. Типы, макросы ошибок и закрытие дескриптора в оригинале неполны. Код сохранён для проверки источника, а не сертифицирован как готовый к запуску.
ArmSoM Docs · Rockchip Linux kernel · EDITORIAL-NOTES
1 Обзор применения
Vendor Storage предназначен для SN, MAC и других данных производителя. Возможности:
- Доступ по уникальному ID
- Надёжная проверка данных
- Восстановление после потери питания
- Чтение и запись с ПК
- Чтение и запись из UBOOT
- Чтение и запись из ядра
- Чтение и запись из приложений Linux
2 Архитектура Vendor Storage

На схеме PC → USB → UBOOT и Linux Application → IOCTL NODE связаны с Vendor Storage API; Kernel также обращается к этому API. Нижний слой Storage API обслуживает EMMC, SPI NOR и NAND.
3 Структура данных
3.1 SPI NOR и EMMC

Схема раскрывает Header / Index / Data внутри блока Vendor. Для SPI NOR указаны начальные 4K и последующая область 28K; в увеличенной области подписаны четыре блока 4K. Для EMMC показаны начальные 3.5M, область 256K и четыре блока 64K. Сохранены исходные обозначения; применимость необходимо проверить по реальной загрузочной разметке. Это не универсальная команда разбиения накопителя.
3.2 SPI NAND / SLC NAND

- MTD: для Vendor Storage требуется раздел
vnvmразмером не менее 512KB. На схеме внутри него показаны четыре блока 4K и Header / Index / Data. - С FTL: четыре блока 4K находятся в зарезервированной области SPI/SLC NAND (FTL). Системный API не может обращаться к этой области.
3.3 Формат записи
| Смещение (B) | Размер (B) | Название |
|---|---|---|
| 0x0000 | 0x0004 | Tag со значением 0x524B5644. |
| 0x0004 | 0x0004 | Version, увеличивается после записи |
| 0x0008 | 0x0002 | Следующий индекс |
| 0x000A | 0x0002 | Всего элементов |
| 0x000C | 0x0002 | Смещение свободного места |
| 0x000E | 0x0002 | Размер свободного места |
| 0x0010 | 0x0002 | Item0->id |
| 0x0012 | 0x0002 | Item0->offset |
| 0x0014 | 0x0002 | Item0->size |
| 0x0016 | 0x0002 | Item0->flag(reversed) |
| 0x0018 | 0x0008 | Item1 |
| … | … | Item x |
| — | — | Данные (EMMC: около 62KB, остальные: около 3.5KB) |
| Size – 0x08 | 0x0004 | Hash |
| Size – 0x04 | 0x0004 | Version2, значение совпадает с Version |
4 Определения ID
| ID | Назначение |
|---|---|
| 0 | Зарезервировано |
| 1 | SN |
| 2 | WIFI MAC |
| 3 | LAN MAC |
| 4 | BT MAC |
| 5 | HDCP 1.4 HDMI |
| 6 | HDCP 1.4 DP |
| 7 | HDCP 2.X |
| 8 | DRM KEY |
| 9 | PLAYREADY Cert |
| 10 | ATTENTION KEY |
| 11 | PLAYREADY ROOT KEY 0 |
| 12 | PLAYREADY ROOT KEY 1 |
| 13 | HDCP 1.4 HDMIRX |
| 14 | SENSOR CALIBRATION (калибровка датчика) |
| 15 | IMEI |
| 16 | LAN_RGMII_DL |
| 17 | EINK_VCOM_ID |
| 18 | FIRMWARE_VER_ID |
| 19 | HDCP_2X_RX_ID |
| 20 | HDCP_2X_HDMIRX_ID |
| 21 – 31 | Резерв RK для будущего использования |
| 32 - 65535 | Для производителя |
Данные в NVM хранятся с выравниванием 64 байта. Минимальное выделение для элемента — 64 байта: запись 1–64 байт занимает 64 байта, запись 65–128 байт — 128 байт.
5 API UBOOT
u-boot/board/rockchip/common/storage/storage.c
vendor_storage_init
int vendor_storage_init(void);
| Поле | Описание |
|---|---|
| Назначение | Инициализация Vendor Storage |
| Вход | Нет |
| Результат | 0: успешно; другое значение: ошибка |
vendor_storage_read
int vendor_storage_read(u32 id, void *pbuf, u32 size);
| Поле | Описание |
|---|---|
| Назначение | Чтение Vendor Storage по ID |
| Вход | id: ID элемента; pbuf: буфер; size: число читаемых байт |
| Результат | -1: ошибка чтения; другое значение: число прочитанных байт |
vendor_storage_write
int vendor_storage_write(u32 id, void *pbuf, u32 size);
| Поле | Описание |
|---|---|
| Назначение | Запись Vendor Storage по ID |
| Вход | id: ID элемента; pbuf: буфер; size: число записываемых байт |
| Результат | 0: запись успешна; другое значение: ошибка записи |
6 API ядра
kernel/drivers/soc/rockchip/rk_vendor_storage.c
kernel/drivers/soc/rockchip/sdmmc_vendor_storage.c
rk_vendor_read
int rk_vendor_read(u32 id, void *pbuf, u32 size);
| Поле | Описание |
|---|---|
| Назначение | Чтение Vendor Storage по ID |
| Вход | id: ID элемента; pbuf: буфер; size: число читаемых байт |
| Результат | -1: ошибка чтения; другое значение: число прочитанных байт |
rk_vendor_write
int rk_vendor_write(u32 id, void *pbuf, u32 size);
| Поле | Описание |
|---|---|
| Назначение | Запись Vendor Storage по ID |
| Вход | id: ID элемента; pbuf: буфер; size: число записываемых байт |
| Результат | 0: запись успешна; другое значение: ошибка записи |
7 Конфигурация ядра
Makefile

#
# Rockchip soc drivers
#
obj-$(CONFIG_MMC_DW_ROCKCHIP) += sdmmc_vendor_storage.o
obj-$(CONFIG_ROCKCHIP_VENDOR_STORAGE) += rk_vendor_storage.o
Menuconfig

CONFIG_ROCKCHIP_VENDOR_STORAGE:
Say y here to enable vendor storage support.
Vendor storage is used for stored SN, MAC, BT ADDR etc.
Symbol: ROCKCHIP_VENDOR_STORAGE [=y]
Type : boolean
Prompt: Rockchip vendor storage support
Location:
-> Device Drivers
-> SOC (System On Chip) specific Drivers
Defined at drivers/soc/rockchip/Kconfig:6
Depends on: ARCH_ROCKCHIP [=y] || COMPILE_TEST
Выберите y для поддержки SN, MAC, BT ADDR и подобных данных. На исходном снимке символ включён ([=y]), тип boolean, путь Device Drivers → SOC (System On Chip) specific Drivers. Зависимость: ARCH_ROCKCHIP [=y] || COMPILE_TEST; определение: drivers/soc/rockchip/Kconfig:6.
8 Демонстрационная утилита ПК
1. Выберите SN, введите значение и нажмите ENTER, чтобы добавить SN в список запросов записи. В примере используется 123SN; состояние на снимке — Not found rockusb.

2. Нажмите Burning для записи в Vendor Storage. На исходном снимке показаны Burning OK. и Found one loader.

3. Выберите SN и нажмите Read для чтения из Vendor Storage. В примере показаны 123SN, Reading OK. и Found one loader.

9 Исходный код утилиты ПК

В оригинале приведён снимок каталога проекта, а не содержимое этих исходных файлов. Усечённое имя ниже оставлено усечённым; скрытый суффикс не восстановлен.
cmLib/
colorEdit/
FontStatic/
grid/
res/
upgradeLib/
ProvisioningTool.aps
ProvisioningTool.cpp
ProvisioningTool.h
ProvisioningTool.rc
ProvisioningTool.vcproj
ProvisioningTool.vcproj.HP-INPRC6N...
ProvisioningToolDlg.cpp
ProvisioningToolDlg.h
ReadMe.txt
resource.h
stdafx.cpp
stdafx.h
targetver.h
10 Утилита ПК: чтение данных
/*----------------------------------------------------------------------
Name : RK_ReadProvisioningData
Desc : Read provisioning data by id
Params : (IN)nID id
(OUT)pDataBuffer: buffer to save data, malloc by caller
(IN|OUT)nBufferSize: in = size of buffer,out = actual data size
(IN)dwLayer: device layer
Return : TRUE: SUCCESSED
FALSE: FAILED
----------------------------------------------------------------------*/
BOOL RK_ReadProvisioningData(USHORT nID,PBYTE pDataBuffer,USHORT &nBufferSize,DWORD dwLayer=0);
Чтение данных подготовки по ID. pDataBuffer выделяется вызывающей стороной. nBufferSize на входе задаёт размер буфера, на выходе — фактический размер данных. dwLayer задаёт слой устройства, по умолчанию 0. Успех — TRUE, ошибка — FALSE.
11 Утилита ПК: запись данных
/*----------------------------------------------------------------------
Name : RK_WriteProvisioningData
Desc : Write provisioning data by id
Params : (IN)nID id
(IN)pDataBuffer: buffer to save data, malloc by caller
(IN)nBufferSize: size of buffer
(IN)dwLayer: device layer
Return : TRUE: SUCCESSED
FALSE: FAILED
----------------------------------------------------------------------*/
BOOL RK_WriteProvisioningData(USHORT nID,PBYTE pDataBuffer,USHORT nBufferSize,DWORD dwLayer=0);
Запись данных подготовки по ID. Вызывающая сторона выделяет pDataBuffer; nBufferSize задаёт размер входного буфера. dwLayer — слой устройства, по умолчанию 0. Успех — TRUE, ошибка — FALSE.
12 Примеры кода Linux
#include <fcntl.h>
#include <sys/ioctl.h>
typedef unsigned short uint16;
typedef unsigned long uint32;
typedef unsigned char uint8;
#define VENDOR_REQ_TAG 0x56524551
#define VENDOR_READ_IO _IOW('v', 0x01, unsigned int)
#define VENDOR_WRITE_IO _IOW('v', 0x02, unsigned int)
#define VENDOR_SN_ID 1
#define VENDOR_WIFI_MAC_ID 2
#define VENDOR_LAN_MAC_ID 3
#define VENDOR_BLUETOOTH_ID 4
struct rk_vendor_req {
u32 tag;
u16 id;
u16 len;
u8 data[1];
};
12.1 Проверка чтения
int vendor_storage_read_test(void)
{
uint32 i;
int ret ;
uint8 p_buf[2048]; /* malloc req buffer or used extern buffer */
struct rk_vendor_req *req;
req = (struct rk_vendor_req *)p_buf;
int sys_fd = open("/dev/vendor_storage",O_RDWR,0);
if(sys_fd < 0){
ERROR("vendor_storage open fail\n");
return -1;
}
req->tag = VENDOR_REQ_TAG;
req->id = VENDOR_SN_ID;
req->len = 512; /* max read length to read*/
ret = ioctl(sys_fd, VENDOR_READ_IO, req);
/* return req->len is the real data length stored in the NV-storage */
if(ret){
ERROR("vendor read error\n");
return -1;
}
return 0;
}
12.2 Проверка записи
int vendor_storage_write_test(void)
{
uint32 i;
int ret ;
uint8 p_buf[2048]; /* malloc req buffer or used extern buffer */
struct rk_vendor_req *req;
req = (struct rk_vendor_req *)p_buf;
int sys_fd = open("/dev/vendor_storage",O_RDWR,0);
if(sys_fd < 0){
ERROR("vendor_storage open fail\n");
return -1;
}
req->tag = VENDOR_REQ_TAG;
req->id = VENDOR_SN_ID;
req->len = 32; /* data len */
for (i = 0; i < 32; i++)
req->data[i] = i;
rknand_print_hex_data("vendor write:", (uint32*)req, req->len + 8);
ret = ioctl(sys_fd, VENDOR_WRITE_IO, req);
if(ret){
ERROR("vendor write error\n");
return -1;
}
return 0;
}
