Documentation/driver-api/nvmem.rst GitHub 원문 ↗

Linux 6.18.37 · Driver API

NVMEM Subsystem

NVMEM provider·cell·consumer API, userspace binary interface와 dynamic layout의 전문 번역입니다.

Source pathDocumentation/driver-api/nvmem.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

nvmem.rst:1-202

NVMEM core는 EEPROM과 eFuse provider를 공통 등록하고 이름 있는 cell 또는 직접 device API로 kernel consumer에 제공합니다. Userspace raw binary access, Device Tree mapping과 동적 layout/post-processing도 지원합니다.

문서 구성
원문 줄내용
1-30Framework 목적
31-92Provider, cell과 lookup
93-139Cell·device consumer API
140-155Reference 해제
156-182Userspace와 Device Tree
183-202Layout과 internal API

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 ===============
4 NVMEM Subsystem
5 ===============
6
7 Srinivas Kandagatla <[email protected]>
8
9 This document explains the NVMEM Framework along with the APIs provided,
10 and how to use it.
11
12 1. Introduction
13 ===============
14 *NVMEM* is the abbreviation for Non Volatile Memory layer. It is used to
15 retrieve configuration of SOC or Device specific data from non volatile
16 memories like eeprom, efuses and so on.
17
18 Before this framework existed, NVMEM drivers like eeprom were stored in
19 drivers/misc, where they all had to duplicate pretty much the same code to
20 register a sysfs file, allow in-kernel users to access the content of the
21 devices they were driving, etc.
22
23 This was also a problem as far as other in-kernel users were involved, since
24 the solutions used were pretty much different from one driver to another, there
25 was a rather big abstraction leak.
26
27 This framework aims at solve these problems. It also introduces DT
28 representation for consumer devices to go get the data they require (MAC
29 Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs.
30
31 NVMEM Providers
32 +++++++++++++++
33
34 NVMEM provider refers to an entity that implements methods to initialize, read
35 and write the non-volatile memory.
36
37 2. Registering/Unregistering the NVMEM provider
38 ===============================================
39
40 A NVMEM provider can register with NVMEM core by supplying relevant
41 nvmem configuration to nvmem_register(), on success core would return a valid
42 nvmem_device pointer.
43
44 nvmem_unregister() is used to unregister a previously registered provider.
45
46 For example, a simple nvram case::
47
48 static int brcm_nvram_probe(struct platform_device *pdev)
49 {
50 struct nvmem_config config = {
51 .name = "brcm-nvram",
52 .reg_read = brcm_nvram_read,
53 };
54 ...
55 config.dev = &pdev->dev;
56 config.priv = priv;
57 config.size = resource_size(res);
58
59 devm_nvmem_register(&config);
60 }
61
62 Device drivers can define and register an nvmem cell using the nvmem_cell_info
63 struct::
64
65 static const struct nvmem_cell_info foo_nvmem_cell = {
66 {
67 .name = "macaddr",
68 .offset = 0x7f00,
69 .bytes = ETH_ALEN,
70 }
71 };
72
73 int nvmem_add_one_cell(nvmem, &foo_nvmem_cell);
74
75 Additionally it is possible to create nvmem cell lookup entries and register
76 them with the nvmem framework from machine code as shown in the example below::
77
78 static struct nvmem_cell_lookup foo_nvmem_lookup = {
79 .nvmem_name = "i2c-eeprom",
80 .cell_name = "macaddr",
81 .dev_id = "foo_mac.0",
82 .con_id = "mac-address",
83 };
84
85 nvmem_add_cell_lookups(&foo_nvmem_lookup, 1);
86
87 NVMEM Consumers
88 +++++++++++++++
89
90 NVMEM consumers are the entities which make use of the NVMEM provider to
91 read from and to NVMEM.
92
93 3. NVMEM cell based consumer APIs
94 =================================
95
96 NVMEM cells are the data entries/fields in the NVMEM.
97 The NVMEM framework provides 3 APIs to read/write NVMEM cells::
98
99 struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name);
100 struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *name);
101
102 void nvmem_cell_put(struct nvmem_cell *cell);
103 void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
104
105 void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len);
106 int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len);
107
108 `*nvmem_cell_get()` apis will get a reference to nvmem cell for a given id,
109 and nvmem_cell_read/write() can then read or write to the cell.
110 Once the usage of the cell is finished the consumer should call
111 `*nvmem_cell_put()` to free all the allocation memory for the cell.
112
113 4. Direct NVMEM device based consumer APIs
114 ==========================================
115
116 In some instances it is necessary to directly read/write the NVMEM.
117 To facilitate such consumers NVMEM framework provides below apis::
118
119 struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
120 struct nvmem_device *devm_nvmem_device_get(struct device *dev,
121 const char *name);
122 struct nvmem_device *nvmem_device_find(void *data,
123 int (*match)(struct device *dev, const void *data));
124 void nvmem_device_put(struct nvmem_device *nvmem);
125 int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset,
126 size_t bytes, void *buf);
127 int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset,
128 size_t bytes, void *buf);
129 int nvmem_device_cell_read(struct nvmem_device *nvmem,
130 struct nvmem_cell_info *info, void *buf);
131 int nvmem_device_cell_write(struct nvmem_device *nvmem,
132 struct nvmem_cell_info *info, void *buf);
133
134 Before the consumers can read/write NVMEM directly, it should get hold
135 of nvmem_controller from one of the `*nvmem_device_get()` api.
136
137 The difference between these apis and cell based apis is that these apis always
138 take nvmem_device as parameter.
139
140 5. Releasing a reference to the NVMEM
141 =====================================
142
143 When a consumer no longer needs the NVMEM, it has to release the reference
144 to the NVMEM it has obtained using the APIs mentioned in the above section.
145 The NVMEM framework provides 2 APIs to release a reference to the NVMEM::
146
147 void nvmem_cell_put(struct nvmem_cell *cell);
148 void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
149 void nvmem_device_put(struct nvmem_device *nvmem);
150 void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem);
151
152 Both these APIs are used to release a reference to the NVMEM and
153 devm_nvmem_cell_put and devm_nvmem_device_put destroys the devres associated
154 with this NVMEM.
155
156 Userspace
157 +++++++++
158
159 6. Userspace binary interface
160 ==============================
161
162 Userspace can read/write the raw NVMEM file located at::
163
164 /sys/bus/nvmem/devices/*/nvmem
165
166 ex::
167
168 hexdump /sys/bus/nvmem/devices/qfprom0/nvmem
169
170 0000000 0000 0000 0000 0000 0000 0000 0000 0000
171 *
172 00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
173 0000000 0000 0000 0000 0000 0000 0000 0000 0000
174 ...
175 *
176 0001000
177
178 7. DeviceTree Binding
179 =====================
180
181 See Documentation/devicetree/bindings/nvmem/nvmem.txt
182
183 8. NVMEM layouts
184 ================
185
186 NVMEM layouts are yet another mechanism to create cells. With the device
187 tree binding it is possible to specify simple cells by using an offset
188 and a length. Sometimes, the cells doesn't have a static offset, but
189 the content is still well defined, e.g. tag-length-values. In this case,
190 the NVMEM device content has to be first parsed and the cells need to
191 be added accordingly. Layouts let you read the content of the NVMEM device
192 and let you add cells dynamically.
193
194 Another use case for layouts is the post processing of cells. With layouts,
195 it is possible to associate a custom post processing hook to a cell. It
196 even possible to add this hook to cells not created by the layout itself.
197
198 9. Internal kernel API
199 ======================
200
201 .. kernel-doc:: drivers/nvmem/core.c
202 :export:
203

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

NVMEM framework의 목적

1-30

Srinivas Kandagatla가 작성한 이 문서는 NVMEM Framework와 제공 API 및 사용 방법을 설명합니다.

NVMEM은 Non Volatile Memory layer의 약자입니다. EEPROM, eFuse 같은 비휘발성 메모리에서 SoC 또는 device별 configuration data를 가져오는 데 사용합니다.

Framework 이전에는 EEPROM 같은 NVMEM driver가 `drivers/misc`에 있었고, sysfs file 등록, in-kernel user의 device content 접근 지원 등 거의 같은 코드를 각 driver가 반복해야 했습니다.

Kernel 내부 consumer가 사용하는 해결 방법도 driver마다 달라 abstraction leak이 컸습니다.

NVMEM framework는 이 문제를 해결하며, consumer device가 MAC address, SoC/revision ID, part number 같은 필요한 data를 NVMEM에서 가져오도록 Device Tree 표현도 도입합니다.

NVMEM framework 역할
EEPROM / eFuse / device storageNVMEM providerNVMEM coreCell or direct-device APIKernel consumer
Device TreeNamed NVMEM cellsMAC / SoC ID / revision / part number

Provider별 구현을 공통 core와 cell abstraction으로 묶어 kernel 및 DT consumer에 제공합니다.

.. SPDX-License-Identifier: GPL-2.0

===============
NVMEM Subsystem
===============

 Srinivas Kandagatla <[email protected]>

This document explains the NVMEM Framework along with the APIs provided,
and how to use it.

1. Introduction
===============
*NVMEM* is the abbreviation for Non Volatile Memory layer. It is used to
retrieve configuration of SOC or Device specific data from non volatile
memories like eeprom, efuses and so on.

Before this framework existed, NVMEM drivers like eeprom were stored in
drivers/misc, where they all had to duplicate pretty much the same code to
register a sysfs file, allow in-kernel users to access the content of the
devices they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from one driver to another, there
was a rather big abstraction leak.

This framework aims at solve these problems. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs.

NVMEM provider 등록과 해제

31-60

NVMEM provider는 비휘발성 메모리를 initialize, read, write하는 method를 구현하는 구성 요소입니다.

Provider는 관련 `nvmem_config`를 `nvmem_register()`에 전달해 NVMEM core에 등록합니다. 성공하면 core가 유효한 `nvmem_device` pointer를 반환합니다. 이전에 등록한 provider는 `nvmem_unregister()`로 해제합니다.

간단한 Broadcom NVRAM 예제는 이름을 `brcm-nvram`, read callback을 `brcm_nvram_read`로 설정합니다. Probe에서 `config.dev`, provider-private data인 `config.priv`, resource size인 `config.size`를 채웁니다.

예제는 device-managed variant인 `devm_nvmem_register(&config)`를 호출해 provider를 등록합니다.

Provider configuration
항목예제 값 또는 API
Name`brcm-nvram`
Read callback`brcm_nvram_read`
Owner device`config.dev = &pdev->dev`
Private data`config.priv = priv`
Size`resource_size(res)`
Register`nvmem_register()` / `devm_nvmem_register()`
Unregister`nvmem_unregister()`

NVMEM Providers
+++++++++++++++

NVMEM provider refers to an entity that implements methods to initialize, read
and write the non-volatile memory.

2. Registering/Unregistering the NVMEM provider
===============================================

A NVMEM provider can register with NVMEM core by supplying relevant
nvmem configuration to nvmem_register(), on success core would return a valid
nvmem_device pointer.

nvmem_unregister() is used to unregister a previously registered provider.

For example, a simple nvram case::

  static int brcm_nvram_probe(struct platform_device *pdev)
  {
        struct nvmem_config config = {
                .name = "brcm-nvram",
                .reg_read = brcm_nvram_read,
        };
        ...
        config.dev = &pdev->dev;
        config.priv = priv;
        config.size = resource_size(res);

        devm_nvmem_register(&config);
  }

Cell 정의와 lookup

61-92

Device driver는 `struct nvmem_cell_info`로 NVMEM cell을 정의하고 등록할 수 있습니다. 예제 `macaddr` cell은 offset `0x7f00`에서 `ETH_ALEN` bytes를 차지하며 `nvmem_add_one_cell()`로 추가합니다.

Machine code에서도 NVMEM cell lookup entry를 만들어 framework에 등록할 수 있습니다. 예제는 NVMEM `i2c-eeprom`의 cell `macaddr`를 consumer device `foo_mac.0`의 connection ID `mac-address`에 연결합니다.

Lookup table은 `nvmem_add_cell_lookups(&foo_nvmem_lookup, 1)`로 등록합니다.

NVMEM consumer는 provider를 사용해 NVMEM을 읽거나 쓰는 구성 요소입니다.

Cell lookup 연결
`i2c-eeprom` provider`macaddr` at `0x7f00`, `ETH_ALEN``nvmem_add_one_cell()`
`nvmem_cell_lookup``foo_mac.0` + `mac-address`Consumer

Provider 내부 offset을 이름 있는 cell로 정의하고 consumer connection에 매핑합니다.


Device drivers can define and register an nvmem cell using the nvmem_cell_info
struct::

  static const struct nvmem_cell_info foo_nvmem_cell = {
        {
                .name                = "macaddr",
                .offset                = 0x7f00,
                .bytes                = ETH_ALEN,
        }
  };

  int nvmem_add_one_cell(nvmem, &foo_nvmem_cell);

Additionally it is possible to create nvmem cell lookup entries and register
them with the nvmem framework from machine code as shown in the example below::

  static struct nvmem_cell_lookup foo_nvmem_lookup = {
        .nvmem_name                = "i2c-eeprom",
        .cell_name                = "macaddr",
        .dev_id                        = "foo_mac.0",
        .con_id                        = "mac-address",
  };

  nvmem_add_cell_lookups(&foo_nvmem_lookup, 1);

NVMEM Consumers
+++++++++++++++

NVMEM consumers are the entities which make use of the NVMEM provider to
read from and to NVMEM.

Cell 기반 consumer API

93-112

NVMEM cell은 NVMEM 안의 data entry 또는 field입니다. Framework는 cell을 가져오고 반환하며 읽고 쓰는 API를 제공합니다.

`nvmem_cell_get()`과 `devm_nvmem_cell_get()`은 주어진 ID의 cell reference를 얻습니다. 일반 reference는 `nvmem_cell_put()`으로 반환하고 managed reference에는 `devm_nvmem_cell_put()`이 대응합니다.

`nvmem_cell_read()`는 cell data와 길이를 읽고, `nvmem_cell_write()`는 buffer와 length를 cell에 기록합니다.

Consumer가 cell 사용을 마치면 `*nvmem_cell_put()`을 호출해 cell을 위해 할당된 메모리를 모두 해제해야 합니다.

Cell consumer API
단계API
Acquire`nvmem_cell_get()` / `devm_nvmem_cell_get()`
Read`nvmem_cell_read(cell, &len)`
Write`nvmem_cell_write(cell, buf, len)`
Release`nvmem_cell_put()` / `devm_nvmem_cell_put()`

3. NVMEM cell based consumer APIs
=================================

NVMEM cells are the data entries/fields in the NVMEM.
The NVMEM framework provides 3 APIs to read/write NVMEM cells::

  struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name);
  struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *name);

  void nvmem_cell_put(struct nvmem_cell *cell);
  void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);

  void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len);
  int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len);

`*nvmem_cell_get()` apis will get a reference to nvmem cell for a given id,
and nvmem_cell_read/write() can then read or write to the cell.
Once the usage of the cell is finished the consumer should call
`*nvmem_cell_put()` to free all the allocation memory for the cell.

직접 NVMEM device consumer API

113-139

일부 consumer는 NVMEM을 직접 읽거나 써야 합니다. 이를 위해 framework는 이름이나 match callback으로 `nvmem_device`를 얻는 API를 제공합니다.

`nvmem_device_get()`과 managed `devm_nvmem_device_get()`은 device와 name으로 controller를 얻고, `nvmem_device_find()`는 caller data와 match callback으로 찾습니다. 일반 reference는 `nvmem_device_put()`으로 반환합니다.

`nvmem_device_read()`와 `nvmem_device_write()`는 offset과 byte count로 raw 범위를 읽고 씁니다. `nvmem_device_cell_read()`와 `nvmem_device_cell_write()`는 `nvmem_cell_info`가 기술한 cell을 주어진 device에서 직접 처리합니다.

Consumer는 직접 I/O를 하기 전에 `*nvmem_device_get()` API 중 하나로 `nvmem_controller`를 확보해야 합니다. Cell 기반 API와 달리 이 API들은 항상 `nvmem_device`를 parameter로 받습니다.

Direct-device API
기능API
Get by name`nvmem_device_get()` / `devm_nvmem_device_get()`
Find by match`nvmem_device_find()`
Raw read/write`nvmem_device_read()` / `nvmem_device_write()`
Cell-info read/write`nvmem_device_cell_read()` / `nvmem_device_cell_write()`
Put`nvmem_device_put()`

4. Direct NVMEM device based consumer APIs
==========================================

In some instances it is necessary to directly read/write the NVMEM.
To facilitate such consumers NVMEM framework provides below apis::

  struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
  struct nvmem_device *devm_nvmem_device_get(struct device *dev,
                                           const char *name);
  struct nvmem_device *nvmem_device_find(void *data,
                        int (*match)(struct device *dev, const void *data));
  void nvmem_device_put(struct nvmem_device *nvmem);
  int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset,
                      size_t bytes, void *buf);
  int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset,
                       size_t bytes, void *buf);
  int nvmem_device_cell_read(struct nvmem_device *nvmem,
                           struct nvmem_cell_info *info, void *buf);
  int nvmem_device_cell_write(struct nvmem_device *nvmem,
                            struct nvmem_cell_info *info, void *buf);

Before the consumers can read/write NVMEM directly, it should get hold
of nvmem_controller from one of the `*nvmem_device_get()` api.

The difference between these apis and cell based apis is that these apis always
take nvmem_device as parameter.

NVMEM reference 해제

140-155

Consumer가 NVMEM을 더 이상 사용하지 않으면 앞 절의 API로 얻은 NVMEM reference를 해제해야 합니다.

Cell reference에는 `nvmem_cell_put()`과 `devm_nvmem_cell_put()`을 사용하고, device reference에는 `nvmem_device_put()`과 `devm_nvmem_device_put()`을 사용합니다.

모두 NVMEM reference를 해제하며, managed put인 `devm_nvmem_cell_put()`과 `devm_nvmem_device_put()`은 해당 NVMEM에 연결된 devres도 파괴합니다.

Reference release
ReferenceManualDevice-managed
Cell`nvmem_cell_put()``devm_nvmem_cell_put()`
Device`nvmem_device_put()``devm_nvmem_device_put()`
Managed 부가 동작-Associated devres 파괴

5. Releasing a reference to the NVMEM
=====================================

When a consumer no longer needs the NVMEM, it has to release the reference
to the NVMEM it has obtained using the APIs mentioned in the above section.
The NVMEM framework provides 2 APIs to release a reference to the NVMEM::

  void nvmem_cell_put(struct nvmem_cell *cell);
  void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
  void nvmem_device_put(struct nvmem_device *nvmem);
  void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem);

Both these APIs are used to release a reference to the NVMEM and
devm_nvmem_cell_put and devm_nvmem_device_put destroys the devres associated
with this NVMEM.

Userspace binary interface와 Device Tree

156-182

Userspace는 `/sys/bus/nvmem/devices/*/nvmem`에 있는 raw NVMEM file을 읽거나 쓸 수 있습니다.

예제는 `hexdump /sys/bus/nvmem/devices/qfprom0/nvmem`으로 Qualcomm fuse provider의 binary content를 출력합니다.

Device Tree binding은 `Documentation/devicetree/bindings/nvmem/nvmem.txt`를 참조합니다.

Userspace raw NVMEM access
NVMEM provider `qfprom0``/sys/bus/nvmem/devices/qfprom0/nvmem``hexdump` or binary writeUserspace
Device Tree`Documentation/devicetree/bindings/nvmem/nvmem.txt`Provider and cell description

NVMEM provider별 sysfs binary file을 직접 읽거나 씁니다.

Userspace
+++++++++

6. Userspace binary interface
==============================

Userspace can read/write the raw NVMEM file located at::

        /sys/bus/nvmem/devices/*/nvmem

ex::

  hexdump /sys/bus/nvmem/devices/qfprom0/nvmem

  0000000 0000 0000 0000 0000 0000 0000 0000 0000
  *
  00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
  0000000 0000 0000 0000 0000 0000 0000 0000 0000
  ...
  *
  0001000

7. DeviceTree Binding
=====================

See Documentation/devicetree/bindings/nvmem/nvmem.txt

동적 layout과 internal kernel API

183-202

NVMEM layout은 cell을 생성하는 또 다른 mechanism입니다. Device Tree binding에서는 offset과 length로 단순 cell을 지정할 수 있습니다.

하지만 tag-length-value처럼 content는 정의되어 있어도 cell offset이 고정되지 않는 경우가 있습니다. 이때 NVMEM device content를 먼저 parse하고 결과에 맞춰 cell을 추가해야 합니다. Layout은 NVMEM content를 읽고 cell을 동적으로 추가하게 해줍니다.

Layout의 다른 용도는 cell post-processing입니다. Cell에 custom post-processing hook을 연결할 수 있고, layout 자체가 만들지 않은 cell에도 hook을 추가할 수 있습니다.

Internal kernel API 문서는 `drivers/nvmem/core.c`의 exported kernel-doc에서 생성합니다.

NVMEM layout 처리
Read NVMEM device contentLayout parserDiscover TLV or dynamic fieldsAdd cells dynamicallyOptional post-processing hookConsumer
`drivers/nvmem/core.c`Exported internal kernel API documentation

고정 offset이 없는 content를 parse해 cell을 만들고 선택적으로 후처리합니다.

8. NVMEM layouts
================

NVMEM layouts are yet another mechanism to create cells. With the device
tree binding it is possible to specify simple cells by using an offset
and a length. Sometimes, the cells doesn't have a static offset, but
the content is still well defined, e.g. tag-length-values. In this case,
the NVMEM device content has to be first parsed and the cells need to
be added accordingly. Layouts let you read the content of the NVMEM device
and let you add cells dynamically.

Another use case for layouts is the post processing of cells. With layouts,
it is possible to associate a custom post processing hook to a cell. It
even possible to add this hook to cells not created by the layout itself.

9. Internal kernel API
======================

.. kernel-doc:: drivers/nvmem/core.c
   :export: