Difference between revisions of "NVMEM overview"

[quality revision] [quality revision]
m (Device tree configuration)
m
 
Applicable for STM32MP13x lines, STM32MP15x lines

This article introduces how NVMEM Linux® framework manages BSEC OTP data and how to read/write from/to it.

1 Framework purpose[edit]

The NVMEM Linux® framework provides a generic interface for the device non-volatile memory data such as:

  • OTP (one-time programmable) fuses
  • EEPROM

It offers kernel space and user space interfaces to read and/or write data such as analog calibration data or MAC address.

2 System overview[edit]

NVMEM sysfs interface NVMEM consumers interface BSEC internal peripheral BSEC PTA OP-TEE OP-TEE linux driver TEE Client APINVMEM overview.png
NVMEM system overview

2.1 Component description[edit]

  • NVMEM user (user space)

The user can use the NVMEM sysfs interface, from a user terminal or a custom application, to read/write data from/to NVMEM device(s) from user space.

  • NVMEM user (kernel space)

User drivers can use the NVMEM API to read/write data from/to NVMEM device(s) from kernel space (such as the analog calibration data used by an ADC driver).

  • NVMEM framework (kernel space)

The NVMEM core provides sysfs interface and NVMEM API. They can be used to implement NVMEM user and NVMEM controller drivers.

  • NVMEM drivers (kernel space)

Provider drivers such as BSEC STM32 ROMEM Linux® driver that exposes BSEC OTP data to the core.

  • TEE framework (kernel space)

The TEE framework provides TEE client API to communicate with secure services, as the services provided by the OP-TEE Linux® driver.

  • OP-TEE (Secure)

The OP-TEE secure OS is running on the Cortex-A in secure mode and exposes secure service with Trusted Applications (TA), as BSEC PTA.

  • NVMEM hardware

NVMEM controller(s) such as the BSEC internal peripheral[1]

2.2 API description[edit]

The NVMEM kernel documentation[2] describes:

  • Kernel space API for NVMEM providers and NVMEM consumers.
  • Userspace binary interface (sysfs).

See also sysfs-bus-nvmem[3] ABI documentation.

3 Configuration[edit]

3.1 Kernel configuration[edit]

Activate NVMEM framework in the kernel configuration through the Linux® menuconfig tool, Menuconfig or how to configure kernel (CONFIG_NVMEM=y):

Device Drivers  --->
   [*] NVMEM Support  --->
      <*>   STMicroelectronics STM32 factory-programmed memory support

3.2 Device tree configuration[edit]

The NVMEM data device tree bindings describe:

  • The location of non-volatile memory data
  • The NVMEM data providers[4]
  • The NVMEM data consumers[5]

The BSEC internal peripheral[1] device tree bindings are explained in BSEC device tree configuration article.

4 How to use the framework[edit]

4.1 How to use NVMEM with sysfs interface[edit]

4.1.1 How to list NVMEM devices[edit]

The available NVMEM devices can be listed in sysfs :

# Example to list nvmem devices

directory /sys/bus/nvmem/devices

Example to list nvmem devices: BSEC is stm32-romem0

 ls /sys/bus/nvmem/devices/
stm32-romem0

The data content of an NVMEM device can be dumped to a binary file, and then displayed.

4.1.2 How to read BSEC lower OTPs using NVMEM[edit]

The 32 lower OTPs Userspace can be read from non-secure when using either:

  • the trusted boot chain (using TF-A)
  • the basic boot chain (using U-Boot SPL)
# Example to read lower nvmem data content dd if=

read/write the raw NVMEM file located at: /sys/bus/nvmem/devices/*/nvmem

For BSEC, the NVEM stm32-romem0

/nvmem of=/tmp/file bs=4 count=32 # Example to display nvmem data content hexdump -C -v /tmp/file

4.1.3 How to read BSEC upper OTPs using NVMEM[edit]

Info white.png Information Only

device, the content of non-secure OTPs can be read but the secured OTPs are masked, theirs values are replaced by 0.

Normally only the 32 lower OTPs can be accessed

when using the basic boot chain, as it doesn't implement secure services (CONFIG_HAVE_ARM_SMCCC). So this section concerns only the trusted boot chain (using TF-A) as SMC feature is available.

Default behavior for and the upper OTPS is normally restricted to security. If user needs more than the 32 lower OTPs, there is an exception management explained in BSEC device tree configuration.

It is then possible to access to some upper NVMEM information.

#
  • Example
  • to
read the MAC address from upper OTP area, using secure services:
  • read all nvmem data content on stm32-romem0 devices
 dd if=/sys/bus/nvmem/devices/stm32-romem0/nvmem of=/tmp/file
skip=57 bs=4 count=2 status=none
 
  • Example to display nvmem data content
 hexdump -C -v /tmp/filesys/bus/nvmem/devices/stm32-romem0/nvmem

Info white.png Information
A dedicated chapter of the reference manual describes the page describe the OTP mapping for STM32MP13 and STM32MP15.

4.1.43 How to write BSEC OTPs using NVMEM[edit]

Warning white.png Warning
The below examples show how to write data to an NVMEM device. This may cause unrecoverable damage to the STM32 device (for example when writing to an OTP area)
Info white.png Information
Note that lower BSEC OTPs are using 2:1 redundancy, so they can be written bit per bit, whereas upper BSEC OTPs only support one time 32-bit programming.

Whatever the boot chain, the full lower NVMEM data content can be written as follows (if we suppose it has been previously read as described above, and updated directly in /tmp/file):

# Example to write lower nvmem data content
, they are automatically locked by driver.

The BSEC OTP can be written by 32-bit word starting at OTP N as follows:

# write OTP N  word by word
 dd if=/tmp/file  of=/sys/bus/nvmem/devices/stm32-romem0/nvmem bs=4 seek=N

or

# write OTP N, all the file in one request
 dd if=/tmp/file  of=/sys/bus/nvmem/devices/stm32-romem0/nvmem bsseek=4*N countoflag=32

Only on Trusted boot chain, and under the condition the device tree authorizes it, an upper NVMEM data can be written.
Example of 32-bit data word writing (filling it with ones) in OTP n°95
seek_bytes

With a file /tmp/file containing the OTP data to write, its size is 32-bit word aligned; for example:

# Create a 4 bytes length file filled with ones, e.g. 0xffffffff)
# Then, write it (32-bits, e.g. 4bytes) to OTP data 95
 dd if=/dev/zero count=1 bs=4 | tr '\000' '\377' > file
# ddCreate if=filea bs=4 seek=95 of=/sys/bus/nvmem/devices/stm32-romem0/nvmem
bytes length file, here 0x00000001 to update one OTP
 echo -n -e '\x01\x00\x00\x00' > /tmp/file 
# Create a 8 bytes length file, here 0x67452301 0xEFCDAB89 to update two OTPs
 echo -n -e '\x01\x23\x45\x67\x89\xAB\xCD\xEF' > /tmp/file 

A lower OTP can be written several time for a bit per bit update if it is not locked.

An upper OTP data can be written only if it is allowed in secure world device tree and only one time; when the upper OTP is written, it is permanent locked at the end of the NVMEM request to avoid ECC issue on second update. For the first example with bs=4, this lock is performed after each OTP update and for the second example with oflag=seek_bytes the lock is done when all the OTPs in input file are updated.

Info white.png Information
When a new OTP value has been written using this SYSFS interface, it may be necessary to reboot the board before reading it back. The OTP value can't be read directly after a write because the OTP value is read in a shadow area not directly in the OTP area.

The full example to write the upper OTP 60 is:

 echo -n -e '\x01\x23\x45\x67' > /tmp/file
 hexdump -C /tmp/file
 00000000  01 23 45 67                                       |.#Eg|
 00000004
 dd if=/tmp/file  of=/sys/bus/nvmem/devices/stm32-romem0/nvmem bs=4 seek=60
 reboot
 << >>
 hexdump -C -v /sys/bus/nvmem/devices/stm32-romem0/nvmem
 ....
 000000f0  01 23 45 67 00 00 00 00  00 00 00 00 00 00 00 00  |.#Eg............|
 ....

The associated output in STM32CubeProgrammer is:

OTP REGISTERS:
---------------------------------------------------------------------------
    ID      |        value    |     status
---------------------------------------------------------------------------
...
    060     |     0x67452301  |  0x40000000
                                 |_[30] Permanent write lock

or in U-Boot

 > fuse read 0 0 96
 ...
Word 0x0000003c: 67452301 00000000 00000000 00000000
...

5 How to trace and debug the framework[edit]

5.1 How to trace[edit]

Ftrace can be used to trace the NVMEM framework:

 cd /sys/kernel/debug/tracing
 cat available_filter_functions | grep nvmem             # Show available filter functions
rtc_nvmem_register
rtc_nvmem_unregister
nvmem_reg_read
bin_attr_nvmem_read
...

Enable the kernel function tracer, then start using nvmem and display the result:

 echo function > current_tracer
 echo "*nvmem*" > set_ftrace_filter                      # Trace all nvmem filter functions
 echo 1 > tracing_on                                     # start ftrace
 hexdump -C -v /sys/bus/nvmem/devices/stm32-romem0/nvmem # dump nvmem
00000000  17 00 00 00 01 80 00 00  00 00 00 00 00 00 00 00  |................|
...
 echo 0 > tracing_on                                     # stop ftrace
 cat trace
# tracer: function
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
         hexdump-478   [000] ....   423.502278: bin_attr_nvmem_read <-sysfs_kf_bin_read
         hexdump-478   [000] ....   423.502290: nvmem_reg_read <-bin_attr_nvmem_read
         hexdump-478   [000] ....   423.515804: bin_attr_nvmem_read <-sysfs_kf_bin_read

6 References[edit]



<noinclude>{{ApplicableFor
|MPUs list=STM32MP13x, STM32MP15x
|MPUs checklist=STM32MP13x,STM32MP15x
}}</noinclude>

{{ReviewsComments|-- [[User:Nathalie Sangouard|Nathalie Sangouard]] ([[User talk:Nathalie Sangouard|talk]]) 15:46, 21 November 2022 (CET)<br />As the article has been set un approved by EX the 21/11/2022, if we want to have it for Wednesday, I need to cancel the TW review and start the Maintainer review. After the approval on wednesday, a TW Review  must be launched}}This article introduces how NVMEM Linux<sup>&reg;</sup> framework manages BSEC OTP data and how to read/write from/to it.<p>


==Framework purpose==
The NVMEM Linux<sup>&reg;</sup> framework provides a generic interface for the device '''non-volatile memory data''' such as:
* OTP (one-time programmable) fuses
* EEPROM
It offers kernel space and user space interfaces to read and/or write data such as analog calibration data or MAC address.

==System overview==
{{ ImageMap|Image:NVMEM_overview.png {{!}} thumb {{!}} 800px {{!}} center{{!}}NVMEM system overview
rect 400 232 500 272rect 470 142 599 173 [[NVMEM_overview#API description|NVMEM sysfs interface]]
rect 612 335 752 368601 233 749 267 [[NVMEM_overview#API description|NVMEM consumers interface]]
rect 478 563 599 605480 660 600 700 [[BSEC internal peripheral]]}}rect 480 536 601 577 [[OP-TEE OTP PTA overview|BSEC PTA]]
rect 232 532 320 570 [[OP-TEE_overview|OP-TEE]]
rect 479 453 600 492 [[OP-TEE_overview#TEE_Linux_driver|OP-TEE linux driver]]
rect 522 412 612 445 [[OP-TEE_overview#TEE_Client_API|TEE Client API]]
}}
===Component description===
* '''NVMEM user''' (user space)
The user can use the NVMEM sysfs interface, from a user terminal or a custom application, to read/write data from/to NVMEM device(s) from user space.
* '''NVMEM user''' (kernel space)
User drivers can use the NVMEM API to read/write data from/to NVMEM device(s) from kernel space (such as the analog calibration data used by an ADC driver).
* '''NVMEM framework''' (kernel space)
The NVMEM core provides sysfs interface and NVMEM API. They can be used to implement NVMEM user and NVMEM controller drivers.
* '''NVMEM drivers''' (kernel space)
Provider drivers such as BSEC STM32 ROMEM Linux<sup>&reg;</sup> driver that exposes BSEC OTP data to the core.
* '''TEE framework''' (kernel space)
The TEE framework provides [[OP-TEE_overview#TEE_Client_API|TEE client API]] to communicate with secure services, as the services provided by the OP-TEE Linux<sup>&reg;</sup> driver.
* ''' OP-TEE'''  (Secure)
The [[OP-TEE overview|'''OP-TEE secure OS''']] is running on the Cortex-A in [[Security_overview|secure mode]] and exposes secure service with '''Trusted Applications (TA)''', as [[OP-TEE OTP PTA overview|BSEC PTA]].
* '''NVMEM hardware'''
NVMEM controller(s) such as the ''BSEC internal peripheral''<ref name="BSEC internal peripheral">[[BSEC internal peripheral]]</ref>


===API description===
The NVMEM kernel documentation<ref name="documentation_nvmem">{{CodeSource | Linux kernel |  Documentation/driver-api/nvmem.rst}}, NVMEM subsytem kernel documentation</ref> describes:
* Kernel space API for NVMEM '''providers''' and NVMEM '''consumers'''.
* Userspace binary interface (sysfs).
See also ''sysfs-bus-nvmem''<ref name="nvmem_abi">{{CodeSource | Linux kernel | Documentation/ABI/stable/sysfs-bus-nvmem}}, NVMEM ABI documentation</ref> ABI documentation.

==Configuration==
===Kernel configuration===
Activate NVMEM framework in the kernel configuration through the Linux<sup>&reg;</sup> menuconfig tool, [[Menuconfig or how to configure kernel | Menuconfig or how to configure kernel ]] (CONFIG_NVMEM=y):
 Device Drivers  --->
    [*] NVMEM Support  ---><*>   STMicroelectronics STM32 factory-programmed memory support

===Device tree configuration===
The NVMEM data device tree bindings describe:
* The location of non-volatile memory data
* The NVMEM data providers<ref name="nvmem dt bindings">{{CodeSource | Linux kernel | Documentation/devicetree/bindings/nvmem/nvmem.yaml}}, NVMEM device tree bindings</ref>

* The NVMEM data consumers<ref name="nvmem-consumer dt bindings">{{CodeSource | Linux kernel | Documentation/devicetree/bindings/nvmem/nvmem-consumer.yaml}}, NVMEM consumer device tree bindings</ref>

The ''BSEC internal peripheral''<ref name="BSEC internal peripheral"/> device tree bindings are explained in [[BSEC device tree configuration]] article.

==How to use the framework==
===How to use NVMEM with sysfs interface===
====How to list NVMEM devices====
The available NVMEM devices can be listed in sysfs:
 # {{highlight| directory {{Highlight|/sys/bus/nvmem/devices}}
Example to '''list''' nvmem devices}}: BSEC is '''stm32-romem0'''{{Board$}} ls /sys/bus/nvmem/devices/
 stm32-romem0The data content of an NVMEM device can be dumped to a binary file, and then displayed.

====How to read BSEC lower OTPs using NVMEM====
The '''32 lower OTPs''' can be read from non-secure when using either:<br/>

* the trusted boot chain (using [[TF-A overview|TF-A]])
* the basic boot chain (using [[U-Boot_overview#SPL:_FSBL_for_basic_boot|U-Boot SPL]])
 # {{highlight|Example to '''read''' lower nvmem data content}}
 {{Board$}} dd if=

====How to read OTPs using NVMEM====

Userspace can read/write the raw NVMEM file located at: {{Highlight|/sys/bus/nvmem/devices/stm32-romem0*/nvmem of=/tmp/file bs=4 count=32
 # {{highlight|Example to '''display''' nvmem data content}}
 {{Board$}} hexdump -C -v /tmp/file

====How to read BSEC upper OTPs using NVMEM====
{{Info|Only the 32 lower OTPs can be accessed when using the basic boot chain, as it doesn't implement secure services (CONFIG_HAVE_ARM_SMCCC). So this section concerns only the trusted boot chain (using [[TF-A overview|TF-A]]) as SMC feature is available.}}

Default behavior for upper OTPS is normally }}

For BSEC, the NVEM '''stm32-romem0''' device, the content of '''non-secure OTPs''' can be read but the '''secured OTPs''' are masked, theirs values are replaced by 0.

Normally only the 32 lower OTPs can be accessed and the upper OTPS is restricted to security. If user needs more than the 32 lower OTPs, there is an exception management explained in [[BSEC device tree configuration]].<br/> 


It is then possible to access to some upper NVMEM information.
 # {{highlight|Example to read the MAC address from upper OTP area, using secure services:}}


* Example to '''read''' all nvmem data content on stm32-romem0 devices{{Board$}} dd if=/sys/bus/nvmem/devices/stm32-romem0/nvmem of=/tmp/fileskip=57 bs=4 count=2 status=none

* Example to '''display''' nvmem data content{{Board$}} hexdump -C -v /tmp/file

{{Info|A dedicated chapter of the [[STM32MP15 resources|reference manual]] describes the OTP mapping.}}sys/bus/nvmem/devices/stm32-romem0/nvmem

{{Info|A dedicated page describe the OTP mapping for [[STM32MP15_OTP_mapping|STM32MP13]] and [[STM32MP15_OTP_mapping|STM32MP15]].}}
====How to write BSEC OTPs using NVMEM====
{{Warning|The below examples show how to write data to an NVMEM device. This may cause unrecoverable damage to the STM32 device (for example when writing to an OTP area)}}

{{Info| Note that lower BSEC OTPs are using 2:1 redundancy, so they can be written bit per bit, whereas upper BSEC OTPs only support one time 32-bit programming. }}

Whatever the boot chain, the full lower NVMEM data content can be written as follows (if we suppose it has been previously read as  described above, and updated directly in /tmp/file):
 # {{highlight|Example to '''write''' lower nvmem data content}}
 {{Board$}} dd if=/tmp/file , they are automatically locked by driver. }}

The BSEC OTP can be written by 32-bit word starting at OTP {{highlight|N}} as follows:

 # {{highlight|'''write''' OTP '''N'''}}  word by word
 {{Board$}} dd if={{highlightParam|/tmp/file}}  of=/sys/bus/nvmem/devices/stm32-romem0/nvmem bs=4 count=32

Only on Trusted boot chain, and under the condition the device tree authorizes it, an upper NVMEM data can be written.<br/> 

Example of 32-bit data word writing (filling it with ones) in OTP n°95:seek={{highlight|N}}
or
 # {{highlight|'''write''' OTP '''N'''}}, all the file in one request
 {{Board$}} dd if={{highlightParam|/tmp/file}}  of=/sys/bus/nvmem/devices/stm32-romem0/nvmem seek={{highlight|4*N}} oflag=seek_bytes

With a file {{highlightParam|/tmp/file}} containing the OTP data to write, its size is 32-bit word aligned; for example:
# Create a 4 bytes length file filled with ones, e.g. 0xffffffff)# Then, write it (32-bits, e.g. 4bytes) to OTP data 95{{Board$}} dd if=/dev/zero count=1 bs=4 | tr '\000' '\377' > file{{Board$}} dd if=file bs=4 seek=95 of=/sys/bus/nvmem/devices/stm32-romem0/nvmem
# Create a 4 bytes length file, here 0x00000001 to update one OTP
 {{Board$}} echo -n -e '\x01\x00\x00\x00' > {{highlightParam|/tmp/file}} 
 # Create a 8 bytes length file, here 0x67452301 0xEFCDAB89 to update two OTPs
 {{Board$}} echo -n -e '\x01\x23\x45\x67\x89\xAB\xCD\xEF' > {{highlightParam|/tmp/file}} 

A lower OTP can be written several time for a bit per bit update if it is not locked.

An upper OTP data can be written only if it is allowed in [[BSEC_device_tree_configuration#BSEC_node_append|secure world device tree]] and only one time; when the upper OTP is written, it is permanent locked at the end of the NVMEM request to avoid ECC issue on second update. For the first example with bs=4, this lock is performed after each OTP update and for the second example with oflag=seek_bytes the lock is done when all the OTPs in input file are updated.
{{Info|When a new OTP value has been written using this SYSFS interface, it may be necessary to reboot the board before reading it back.  The OTP value can't be read directly after a write because the OTP value is read in a shadow area not directly in the OTP area.}}
==How The full example to write the upper OTP 60 is:

 {{Board$}} echo -n -e {{highlight|'\x01\x23\x45\x67'}} > /tmp/file
  hexdump -C /tmp/file
  00000000  {{highlight|01 23 45 67}}                                       |.#Eg|
  00000004
 {{Board$}} dd if=/tmp/file  of=/sys/bus/nvmem/devices/stm32-romem0/nvmem bs=4 seek={{highlightParam|60}}
 {{Board$}} reboot<< >>
 {{Board$}} hexdump -C -v /sys/bus/nvmem/devices/stm32-romem0/nvmem
  ....
  {{highlightParam|000000f0}}  {{highlight|01 23 45 67}} 00 00 00 00  00 00 00 00 00 00 00 00  |.#Eg............|
  ....

The associated output in [[STM32CubeProgrammer#How_to_fuse_STM32MP15x_OTP|STM32CubeProgrammer]] is: <br>


 OTP REGISTERS:
 ---------------------------------------------------------------------------
     ID      |        value    |     status
 ---------------------------------------------------------------------------
 ...
     060     |     0x67452301  |  0x40000000
                                  |_[30] Permanent write lock

or in [[How_to_update_OTP_with_U-Boot|U-Boot]] 

 {{U-Boot$}} > fuse read 0 0 96
  ...
 Word 0x0000003c: 67452301 00000000 00000000 00000000
 ...

==How to trace and debug the framework==
===How to trace===
[[Ftrace]] can be used to trace the NVMEM framework:
 {{Board$}} cd /sys/kernel/debug/tracing
 {{Board$}} cat available_filter_functions | grep nvmem             # Show available filter functions
 rtc_nvmem_register
 rtc_nvmem_unregister
 nvmem_reg_read
 bin_attr_nvmem_read
 ...
Enable the kernel function tracer, then start using nvmem and display the result:
 {{Board$}} echo function > current_tracer
 {{Board$}} echo "*nvmem*" > set_ftrace_filter                      # Trace all nvmem filter functions
 {{Board$}} echo 1 > tracing_on                                     # start ftrace
 {{Board$}} hexdump -C -v /sys/bus/nvmem/devices/stm32-romem0/nvmem # dump nvmem
 00000000  17 00 00 00 01 80 00 00  00 00 00 00 00 00 00 00  |................|
 ...
 {{Board$}} echo 0 > tracing_on                                     # stop ftrace
 {{Board$}} cat trace
 # tracer: function
 #
 #                              _-----=> irqs-off
 #                             / _----=> need-resched
 #                            | / _---=> hardirq/softirq
 #                            || / _--=> preempt-depth
 #                            ||| /     delay
 #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
 #              | |       |   ||||       |         |
          hexdump-478   [000] ....   423.502278: bin_attr_nvmem_read <-sysfs_kf_bin_read
          hexdump-478   [000] ....   423.502290: nvmem_reg_read <-bin_attr_nvmem_read
          hexdump-478   [000] ....   423.515804: bin_attr_nvmem_read <-sysfs_kf_bin_read

==References==
<references />
<noinclude>

{{ArticleBasedOnModel | Framework_overview_article_model}}
{{PublicationRequestId | 10397 | 2019-01-21 | AnneJ}}
[[Category:Persistent storage]]</noinclude>
(27 intermediate revisions by 5 users not shown)
Line 1: Line 1:
  +
<noinclude>{{ApplicableFor
  +
|MPUs list=STM32MP13x, STM32MP15x
  +
|MPUs checklist=STM32MP13x,STM32MP15x
  +
}}</noinclude>
  +
{{ReviewsComments|-- [[User:Nathalie Sangouard|Nathalie Sangouard]] ([[User talk:Nathalie Sangouard|talk]]) 15:46, 21 November 2022 (CET)<br />As the article has been set un approved by EX the 21/11/2022, if we want to have it for Wednesday, I need to cancel the TW review and start the Maintainer review. After the approval on wednesday, a TW Review  must be launched}}
 
This article introduces how NVMEM Linux<sup>&reg;</sup> framework manages BSEC OTP data and how to read/write from/to it.<p>
 
This article introduces how NVMEM Linux<sup>&reg;</sup> framework manages BSEC OTP data and how to read/write from/to it.<p>
   
Line 8: Line 13:
   
 
==System overview==
 
==System overview==
{{
+
{{ ImageMap|Image:NVMEM_overview.png {{!}} thumb {{!}} 800px {{!}} center{{!}}
ImageMap|Image:NVMEM_overview.png {{!}} thumb {{!}} 800px {{!}} center{{!}} NVMEM system overview
+
rect 470 142 599 173 [[NVMEM_overview#API description|NVMEM sysfs interface]]
rect 400 232 500 272 [[NVMEM_overview#API description|NVMEM sysfs interface]]
+
rect 601 233 749 267 [[NVMEM_overview#API description|NVMEM consumers interface]]
rect 612 335 752 368 [[NVMEM_overview#API description|NVMEM consumers interface]]
+
rect 480 660 600 700 [[BSEC internal peripheral]]
rect 478 563 599 605 [[BSEC internal peripheral]]
+
rect 480 536 601 577 [[OP-TEE OTP PTA overview|BSEC PTA]]
  +
rect 232 532 320 570 [[OP-TEE_overview|OP-TEE]]
  +
rect 479 453 600 492 [[OP-TEE_overview#TEE_Linux_driver|OP-TEE linux driver]]
  +
rect 522 412 612 445 [[OP-TEE_overview#TEE_Client_API|TEE Client API]]
 
}}
 
}}
  +
 
===Component description===
 
===Component description===
 
* '''NVMEM user''' (user space)
 
* '''NVMEM user''' (user space)
Line 22: Line 31:
 
The NVMEM core provides sysfs interface and NVMEM API. They can be used to implement NVMEM user and NVMEM controller drivers.
 
The NVMEM core provides sysfs interface and NVMEM API. They can be used to implement NVMEM user and NVMEM controller drivers.
 
* '''NVMEM drivers''' (kernel space)
 
* '''NVMEM drivers''' (kernel space)
Provider drivers such as BSEC Linux<sup>&reg;</sup> driver that exposes OTP data to the core.
+
Provider drivers such as STM32 ROMEM Linux<sup>&reg;</sup> driver that exposes BSEC OTP data to the core.
  +
* '''TEE framework''' (kernel space)
  +
The TEE framework provides [[OP-TEE_overview#TEE_Client_API|TEE client API]] to communicate with secure services, as the services provided by the OP-TEE Linux<sup>&reg;</sup> driver.
  +
* ''' OP-TEE'''  (Secure)
  +
The [[OP-TEE overview|'''OP-TEE secure OS''']] is running on the Cortex-A in [[Security_overview|secure mode]] and exposes secure service with '''Trusted Applications (TA)''', as [[OP-TEE OTP PTA overview|BSEC PTA]].
 
* '''NVMEM hardware'''
 
* '''NVMEM hardware'''
 
NVMEM controller(s) such as the ''BSEC internal peripheral''<ref name="BSEC internal peripheral">[[BSEC internal peripheral]]</ref>
 
NVMEM controller(s) such as the ''BSEC internal peripheral''<ref name="BSEC internal peripheral">[[BSEC internal peripheral]]</ref>
Line 49: Line 62:
 
===How to use NVMEM with sysfs interface===
 
===How to use NVMEM with sysfs interface===
 
====How to list NVMEM devices====
 
====How to list NVMEM devices====
The available NVMEM devices can be listed in sysfs:
+
The available NVMEM devices can be listed in sysfs directory {{Highlight|/sys/bus/nvmem/devices}}
# {{highlight|Example to '''list''' nvmem devices}}
+
  +
Example to '''list''' nvmem devices: BSEC is '''stm32-romem0'''
 
  {{Board$}} ls /sys/bus/nvmem/devices/
 
  {{Board$}} ls /sys/bus/nvmem/devices/
 
  stm32-romem0
 
  stm32-romem0
The data content of an NVMEM device can be dumped to a binary file, and then displayed.
 
   
====How to read BSEC lower OTPs using NVMEM====
+
====How to read OTPs using NVMEM====
The '''32 lower OTPs''' can be read from non-secure when using either:<br/>
+
 
* the trusted boot chain (using [[TF-A overview|TF-A]])
+
Userspace can read/write the raw NVMEM file located at: {{Highlight|/sys/bus/nvmem/devices/*/nvmem}}
* the basic boot chain (using [[U-Boot_overview#SPL:_FSBL_for_basic_boot|U-Boot SPL]])
+
 
# {{highlight|Example to '''read''' lower nvmem data content}}
+
For BSEC, the NVEM '''stm32-romem0''' device, the content of '''non-secure OTPs''' can be read but the '''secured OTPs''' are masked, theirs values are replaced by 0.
{{Board$}} dd if=/sys/bus/nvmem/devices/stm32-romem0/nvmem of=/tmp/file bs=4 count=32
+
 
# {{highlight|Example to '''display''' nvmem data content}}
+
Normally only the 32 lower OTPs can be accessed and the upper OTPS is restricted to security. If user needs more than the 32 lower OTPs, there is an exception management explained in [[BSEC device tree configuration]].
{{Board$}} hexdump -C -v /tmp/file
 
   
====How to read BSEC upper OTPs using NVMEM====
+
* Example to '''read''' all nvmem data content on stm32-romem0 devices
{{Info|Only the 32 lower OTPs can be accessed when using the basic boot chain, as it doesn't implement secure services (CONFIG_HAVE_ARM_SMCCC). So this section concerns only the trusted boot chain (using [[TF-A overview|TF-A]]) as SMC feature is available.}}
+
{{Board$}} dd if=/sys/bus/nvmem/devices/stm32-romem0/nvmem of=/tmp/file
   
Default behavior for upper OTPS is normally restricted to security. If user needs more than the 32 lower OTPs, there is an exception management explained in [[BSEC device tree configuration]].<br/>
+
* Example to '''display''' nvmem data content
  +
{{Board$}} hexdump -C -v /sys/bus/nvmem/devices/stm32-romem0/nvmem
   
It is then possible to access to some upper NVMEM information.
+
{{Info|A dedicated page describe the OTP mapping for [[STM32MP15_OTP_mapping|STM32MP13]] and [[STM32MP15_OTP_mapping|STM32MP15]].}}
# {{highlight|Example to read the MAC address from upper OTP area, using secure services:}}
 
{{Board$}} dd if=/sys/bus/nvmem/devices/stm32-romem0/nvmem of=/tmp/file skip=57 bs=4 count=2 status=none
 
{{Board$}} hexdump -C -v /tmp/file
 
   
{{Info|A dedicated chapter of the [[STM32MP15 resources|reference manual]] describes the OTP mapping.}}
 
 
====How to write BSEC OTPs using NVMEM====
 
====How to write BSEC OTPs using NVMEM====
  +
 
{{Warning|The below examples show how to write data to an NVMEM device. This may cause unrecoverable damage to the STM32 device (for example when writing to an OTP area)}}
 
{{Warning|The below examples show how to write data to an NVMEM device. This may cause unrecoverable damage to the STM32 device (for example when writing to an OTP area)}}
   
{{Info| Note that lower OTPs are using 2:1 redundancy, so they can be written bit per bit, whereas upper OTPs only support one time 32-bit programming. }}
+
{{Info| Note that lower BSEC OTPs are using 2:1 redundancy, so they can be written bit per bit, whereas upper BSEC OTPs only support one time 32-bit programming, they are automatically locked by driver. }}
  +
 
  +
The BSEC OTP can be written by 32-bit word starting at OTP {{highlight|N}} as follows:
  +
 
  +
# {{highlight|'''write''' OTP '''N'''}}  word by word
  +
{{Board$}} dd if={{highlightParam|/tmp/file}}  of=/sys/bus/nvmem/devices/stm32-romem0/nvmem bs=4 seek={{highlight|N}}
  +
or
  +
# {{highlight|'''write''' OTP '''N'''}}, all the file in one request
  +
{{Board$}} dd if={{highlightParam|/tmp/file}}  of=/sys/bus/nvmem/devices/stm32-romem0/nvmem seek={{highlight|4*N}} oflag=seek_bytes
   
Whatever the boot chain, the full lower NVMEM data content can be written as follows (if we suppose it has been previously read as  described above, and updated directly in /tmp/file):
+
With a file {{highlightParam|/tmp/file}} containing the OTP data to write, its size is 32-bit word aligned; for example:
# {{highlight|Example to '''write''' lower nvmem data content}}
 
{{Board$}} dd if=/tmp/file of=/sys/bus/nvmem/devices/stm32-romem0/nvmem bs=4 count=32
 
   
Only on Trusted boot chain, and under the condition the device tree authorizes it, an upper NVMEM data can be written.<br/>
 
Example of 32-bit data word writing (filling it with ones) in OTP n°95:
 
 
  # Create a 4 bytes length file filled with ones, e.g. 0xffffffff)
 
  # Create a 4 bytes length file filled with ones, e.g. 0xffffffff)
# Then, write it (32-bits, e.g. 4bytes) to OTP data 95
 
 
  {{Board$}} dd if=/dev/zero count=1 bs=4 | tr '\000' '\377' > file
 
  {{Board$}} dd if=/dev/zero count=1 bs=4 | tr '\000' '\377' > file
  {{Board$}} dd if=file bs=4 seek=95 of=/sys/bus/nvmem/devices/stm32-romem0/nvmem
+
# Create a 4 bytes length file, here 0x00000001 to update one OTP
  +
  {{Board$}} echo -n -e '\x01\x00\x00\x00' > {{highlightParam|/tmp/file}}
  +
# Create a 8 bytes length file, here 0x67452301 0xEFCDAB89 to update two OTPs
  +
{{Board$}} echo -n -e '\x01\x23\x45\x67\x89\xAB\xCD\xEF' > {{highlightParam|/tmp/file}}
  +
 
  +
A lower OTP can be written several time for a bit per bit update if it is not locked.
  +
 
  +
An upper OTP data can be written only if it is allowed in [[BSEC_device_tree_configuration#BSEC_node_append|secure world device tree]] and only one time; when the upper OTP is written, it is permanent locked at the end of the NVMEM request to avoid ECC issue on second update. For the first example with bs=4, this lock is performed after each OTP update and for the second example with oflag=seek_bytes the lock is done when all the OTPs in input file are updated.
   
 
{{Info|When a new OTP value has been written using this SYSFS interface, it may be necessary to reboot the board before reading it back.  The OTP value can't be read directly after a write because the OTP value is read in a shadow area not directly in the OTP area.}}
 
{{Info|When a new OTP value has been written using this SYSFS interface, it may be necessary to reboot the board before reading it back.  The OTP value can't be read directly after a write because the OTP value is read in a shadow area not directly in the OTP area.}}
  +
  +
The full example to write the upper OTP 60 is:
  +
  +
{{Board$}} echo -n -e {{highlight|'\x01\x23\x45\x67'}} > /tmp/file
  +
  hexdump -C /tmp/file
  +
  00000000  {{highlight|01 23 45 67}}                                      |.#Eg|
  +
  00000004
  +
{{Board$}} dd if=/tmp/file  of=/sys/bus/nvmem/devices/stm32-romem0/nvmem bs=4 seek={{highlightParam|60}}
  +
{{Board$}} reboot
  +
  << >>
  +
{{Board$}} hexdump -C -v /sys/bus/nvmem/devices/stm32-romem0/nvmem
  +
  ....
  +
  {{highlightParam|000000f0}}  {{highlight|01 23 45 67}} 00 00 00 00  00 00 00 00 00 00 00 00  |.#Eg............|
  +
  ....
  +
  +
The associated output in [[STM32CubeProgrammer#How_to_fuse_STM32MP15x_OTP|STM32CubeProgrammer]] is: <br>
  +
  +
OTP REGISTERS:
  +
---------------------------------------------------------------------------
  +
    ID      |        value    |    status
  +
---------------------------------------------------------------------------
  +
...
  +
    060    |    0x67452301  |  0x40000000
  +
                                  |_[30] Permanent write lock
  +
  +
or in [[How_to_update_OTP_with_U-Boot|U-Boot]]
  +
  +
{{U-Boot$}} > fuse read 0 0 96
  +
  ...
  +
Word 0x0000003c: 67452301 00000000 00000000 00000000
  +
...
   
 
==How to trace and debug the framework==
 
==How to trace and debug the framework==