Part 1
요약·해설
SoC-specific controller와 device driver의 many-to-many 관계, runtime reconfiguration, callback 및 device switching 계약을 설명합니다.
single to hex · SDR/DDR
XIP · scrambling · timing
bulk · scatter · async/sync
Part 2
접을 수 있는 영어 원문 전체
영어 원문 전체 펼치기
86EDEED04DC5A62C1AD8E52BAAAF17E18CF0843ABE046A5C867DE269ECDA715F
.. _mspi_api:
Multi-bit SPI Bus
#################
The MSPI (multi-bit SPI) is provided as a generic API to accommodate
advanced SPI peripherals and devices that typically require command,
address and data phases, and multiple signal lines during these phases.
While the API supports advanced features such as :term:`XIP` and scrambling,
it is also compatible with generic SPI.
.. contents::
:local:
:depth: 2
.. _mspi-controller-api:
MSPI Controller API
*******************
Zephyr's MSPI controller API may be used when a multi-bit SPI controller
is present. E.g. Ambiq MSPI, QSPI, OSPI, Flexspi, etc.
The API supports single to hex SDR/DDR IO with variable latency and advanced
features such as :term:`XIP` and scrambling. Applicable devices include but
not limited to high-speed, high density flash/psram memory devices, displays
and sensors.
The MSPI interface contains controller drivers that are SoC platform specific
and implement the MSPI APIs, and device drivers that reference these APIs.
The relationship between the controller and device drivers is many-to-many to
allow for easy switching between platforms.
Here is a list of generic steps for initializing the MSPI controller and the
MSPI bus inside the device driver initialization function:
#. Initialize the data structure of the MSPI controller driver instance.
The usual device defining macros such as :c:macro:`DEVICE_DT_INST_DEFINE`
can be used, and the initialization function, config and data provided
as a parameter to the macro.
#. Initialize the hardware, including but not limited to:
* Check :c:struct:`mspi_cfg` against hardware's own capabilities to prevent
incorrect usages.
* Setup default pinmux.
* Setup the clock for the controller.
* Power on the hardware.
* Configure the hardware using :c:struct:`mspi_cfg` and possibly more
platform specific settings.
* Usually, the :c:struct:`mspi_cfg` is filled from device tree and contains
static, boot time parameters. However, if needed, one can use :c:func:`mspi_config`
to re-initialize the hardware with new parameters during runtime.
* Release any lock if applicable.
#. Perform device driver initialization. As usually, :c:macro:`DEVICE_DT_INST_DEFINE`
can be used. Inside device driver initialization function, perform the following
required steps.
#. Call :c:func:`mspi_dev_config` with device specific hardware settings obtained
from device datasheets.
* The :c:struct:`mspi_dev_cfg` should be filled by device tree and helper macro
:c:macro:`MSPI_DEVICE_CONFIG_DT` can be used.
* The controller driver should then validate the members of :c:struct:`mspi_dev_cfg`
to prevent incorrect usage.
* The controller driver should implement a mutex to protect from accidental access.
* The controller driver may also switch between different devices based on
:c:struct:`mspi_dev_id`.
#. Call API for additional setups if supported by hardware
* :c:func:`mspi_xip_config` for :term:`XIP` feature
* :c:func:`mspi_scramble_config` for scrambling feature
* :c:func:`mspi_timing_config` for platform specific timing setup.
#. Register any callback with :c:func:`mspi_register_callback` if needed.
#. Release the controller mutex lock.
Transceive
==========
The transceive request is of type :c:struct:`mspi_xfer` which allows dynamic change to
the transfer related settings once the mode of operation is determined and configured
by :c:func:`mspi_dev_config`.
The API also supports bulk transfers with different starting addresses and sizes with
:c:struct:`mspi_xfer_packet`. However, it is up to the controller implementation
whether to support scatter IO and callback management. The controller can determine
which user callback to trigger based on :c:enum:`mspi_bus_event_cb_mask` upon completion
of each async/sync transfer if the callback had been registered using
:c:func:`mspi_register_callback`. Or not to trigger any callback at all with
:c:enum:`MSPI_BUS_NO_CB` even if the callbacks are already registered.
In which case that a controller supports hardware command queue, user could take full
advantage of the hardware performance if scatter IO and callback management are supported
by the driver implementation.
Device Tree
===========
Here is an example for defining an MSPI controller in device tree:
The mspi controller's bindings should reference mspi-controller.yaml as one of the base.
.. code-block:: devicetree
mspi0: mspi@400 {
status = "okay";
compatible = "zephyr,mspi-emul-controller";
reg = < 0x400 0x4 >;
#address-cells = < 0x1 >;
#size-cells = < 0x0 >;
clock-frequency = < 0x17d7840 >;
op-mode = "MSPI_CONTROLLER";
duplex = "MSPI_HALF_DUPLEX";
ce-gpios = < &gpio0 0x5 0x1 >, < &gpio0 0x12 0x1 >;
dqs-support;
pinctrl-0 = < &pinmux-mspi0 >;
pinctrl-names = "default";
};
Here is an example for defining an MSPI device in device tree:
The mspi device's bindings should reference mspi-device.yaml as one of the base.
.. code-block:: devicetree
&mspi0 {
mspi_dev0: mspi_dev0@0 {
status = "okay";
compatible = "zephyr,mspi-emul-device";
reg = < 0x0 >;
size = < 0x10000 >;
mspi-max-frequency = < 0x2dc6c00 >;
mspi-io-mode = "MSPI_IO_MODE_QUAD";
mspi-data-rate = "MSPI_DATA_RATE_SINGLE";
mspi-hardware-ce-num = < 0x0 >;
read-instruction = < 0xb >;
write-instruction = < 0x2 >;
instruction-length = "INSTR_1_BYTE";
address-length = "ADDR_4_BYTE";
rx-dummy = < 0x8 >;
tx-dummy = < 0x0 >;
xip-config = < 0x0 0x0 0x0 0x0 >;
ce-break-config = < 0x0 0x0 >;
};
};
User should specify target operating parameters in the DTS such as ``mspi-max-frequency``,
``mspi-io-mode`` and ``mspi-data-rate`` even though they may subject to change during runtime.
It should represent the typical configuration of the device during normal operations.
Multi Peripheral
================
With :c:struct:`mspi_dev_id` defined as collection of the device index and CE GPIO from
device tree, the API supports multiple devices on the same controller instance.
The controller driver implementation may or may not support device switching,
which can be performed either by software or by hardware. If the switching is handled
by software, it should be performed in :c:func:`mspi_dev_config` call.
The device driver should record the current operating conditions of the device to support
software controlled device switching by saving and updating :c:struct:`mspi_dev_cfg` and
other relevant mspi struct or private data structures. In particular, :c:struct:`mspi_dev_id`
which contains the identity of the device needs to be used for every API call.
Configuration Options
*********************
Related configuration options:
* :kconfig:option:`CONFIG_MSPI`
* :kconfig:option:`CONFIG_MSPI_ASYNC`
* :kconfig:option:`CONFIG_MSPI_PERIPHERAL`
* :kconfig:option:`CONFIG_MSPI_XIP`
* :kconfig:option:`CONFIG_MSPI_SCRAMBLE`
* :kconfig:option:`CONFIG_MSPI_TIMING`
* :kconfig:option:`CONFIG_MSPI_INIT_PRIORITY`
* :kconfig:option:`CONFIG_MSPI_COMPLETION_TIMEOUT_TOLERANCE`
API Reference
*************
.. doxygengroup:: mspi_interface
Part 3
한국어 전문 번역
MSPI(multi-bit SPI)는 command·address·data phase가 있고 각 phase에서 여러 signal line을 쓰는 고급 SPI peripheral과 device를 수용하기 위한 범용 API입니다. XIP와 scrambling 같은 고급 기능을 지원하면서 일반 SPI와도 호환됩니다.
MSPI Controller API
Ambiq MSPI, QSPI, OSPI, FlexSPI 같은 multi-bit SPI controller가 있을 때 Zephyr MSPI controller API를 사용할 수 있습니다.
이 API는 variable latency와 함께 single부터 hex까지의 SDR/DDR I/O를 지원하고 XIP와 scrambling 같은 고급 기능도 제공합니다. 적용 대상에는 high-speed·high-density flash/PSRAM memory device, display, sensor 등이 포함되며 여기에만 한정되지는 않습니다.
MSPI interface는 SoC platform에 특화돼 MSPI API를 구현하는 controller driver와 그 API를 참조하는 device driver로 구성됩니다. Controller와 device driver 관계는 platform을 쉽게 전환할 수 있도록 many-to-many입니다.
Device driver 초기화 함수 안에서 MSPI controller와 bus를 초기화하는 일반적인 순서는 다음과 같습니다.
- MSPI controller driver instance의 자료 구조를 초기화합니다.
DEVICE_DT_INST_DEFINE같은 일반적인 device 정의 macro를 사용하고, initialization function·config·data를 macro parameter로 제공할 수 있습니다. - Hardware를 초기화합니다. 다음 작업을 포함하되 여기에만 한정되지는 않습니다.
mspi_cfg를 hardware 자체 capability와 대조해 잘못 사용하는 것을 방지합니다.- Default pinmux를 설정합니다.
- Controller clock을 설정합니다.
- Hardware 전원을 켭니다.
mspi_cfg와 필요할 경우 platform-specific setting을 사용해 hardware를 구성합니다.mspi_cfg는 보통 devicetree에서 채우며 static boot-time parameter를 담습니다. 필요하다면 runtime 중mspi_config()를 호출해 새 parameter로 hardware를 다시 초기화할 수 있습니다.- 해당하는 경우 lock을 해제합니다.
- Device driver를 초기화합니다. 일반적으로
DEVICE_DT_INST_DEFINE를 사용할 수 있으며, device driver initialization function 안에서 다음 필수 단계를 수행합니다.- Device datasheet에서 얻은 device-specific hardware setting으로
mspi_dev_config()를 호출합니다.mspi_dev_cfg는 devicetree에서 채워야 하며MSPI_DEVICE_CONFIG_DThelper macro를 사용할 수 있습니다.- Controller driver는 잘못된 사용을 방지하도록
mspi_dev_cfgmember를 검증해야 합니다. - Controller driver는 우발적인 access를 막는 mutex를 구현해야 합니다.
- Controller driver는
mspi_dev_id에 따라 서로 다른 device 사이를 전환할 수도 있습니다.
- Hardware가 지원한다면 추가 설정 API를 호출합니다.
mspi_xip_config(): XIP 기능mspi_scramble_config(): scrambling 기능mspi_timing_config(): platform-specific timing 설정
- 필요하다면
mspi_register_callback()으로 callback을 등록합니다. - Controller mutex lock을 해제합니다.
- Device datasheet에서 얻은 device-specific hardware setting으로
Transceive
Transceive request는 mspi_xfer type입니다. mspi_dev_config()으로 operation mode를 결정하고 구성한 뒤에도 transfer 관련 setting을 동적으로 바꿀 수 있습니다.
mspi_xfer_packet을 사용하면 서로 다른 starting address와 size를 가진 bulk transfer도 지원합니다. 다만 scatter I/O와 callback management를 지원할지는 controller 구현에 달려 있습니다.
Callback을 mspi_register_callback()으로 등록했다면 controller는 각 asynchronous/synchronous transfer가 끝날 때 mspi_bus_event_cb_mask 값에 따라 호출할 user callback을 결정할 수 있습니다. 이미 callback이 등록돼 있어도 MSPI_BUS_NO_CB를 사용하면 callback을 전혀 호출하지 않을 수 있습니다.
Controller가 hardware command queue를 지원하고 driver 구현도 scatter I/O와 callback management를 제공한다면 사용자는 hardware 성능을 충분히 활용할 수 있습니다.
Device Tree
다음은 devicetree에서 MSPI controller를 정의하는 예입니다. MSPI controller binding은 base 가운데 하나로 mspi-controller.yaml을 참조해야 합니다.
mspi0: mspi@400 {
status = "okay";
compatible = "zephyr,mspi-emul-controller";
reg = < 0x400 0x4 >;
#address-cells = < 0x1 >;
#size-cells = < 0x0 >;
clock-frequency = < 0x17d7840 >;
op-mode = "MSPI_CONTROLLER";
duplex = "MSPI_HALF_DUPLEX";
ce-gpios = < &gpio0 0x5 0x1 >, < &gpio0 0x12 0x1 >;
dqs-support;
pinctrl-0 = < &pinmux-mspi0 >;
pinctrl-names = "default";
};다음은 devicetree에서 MSPI device를 정의하는 예입니다. MSPI device binding은 base 가운데 하나로 mspi-device.yaml을 참조해야 합니다.
&mspi0 {
mspi_dev0: mspi_dev0@0 {
status = "okay";
compatible = "zephyr,mspi-emul-device";
reg = < 0x0 >;
size = < 0x10000 >;
mspi-max-frequency = < 0x2dc6c00 >;
mspi-io-mode = "MSPI_IO_MODE_QUAD";
mspi-data-rate = "MSPI_DATA_RATE_SINGLE";
mspi-hardware-ce-num = < 0x0 >;
read-instruction = < 0xb >;
write-instruction = < 0x2 >;
instruction-length = "INSTR_1_BYTE";
address-length = "ADDR_4_BYTE";
rx-dummy = < 0x8 >;
tx-dummy = < 0x0 >;
xip-config = < 0x0 0x0 0x0 0x0 >;
ce-break-config = < 0x0 0x0 >;
};
};Runtime 중 값이 바뀔 수 있더라도 사용자는 mspi-max-frequency, mspi-io-mode, mspi-data-rate 같은 target operating parameter를 DTS에 명시해야 합니다. 이 값은 normal operation 중 device의 대표적인 configuration을 나타내야 합니다.
Multi Peripheral
mspi_dev_id는 devicetree에서 가져온 device index와 CE GPIO의 집합으로 정의됩니다. 이를 이용해 API는 하나의 controller instance에 연결된 여러 device를 지원합니다.
Controller driver 구현은 device switching을 지원할 수도, 지원하지 않을 수도 있습니다. Switching은 software 또는 hardware가 처리할 수 있으며, software가 처리한다면 mspi_dev_config() 호출 안에서 수행해야 합니다.
Software-controlled device switching을 지원하려면 device driver가 mspi_dev_cfg와 그 밖의 관련 MSPI 구조체 또는 private data structure를 저장·갱신해 현재 device operating condition을 기록해야 합니다. 특히 device identity를 담는 mspi_dev_id를 모든 API 호출에서 사용해야 합니다.
Configuration Options
관련 configuration option은 다음과 같습니다.
CONFIG_MSPICONFIG_MSPI_ASYNCCONFIG_MSPI_PERIPHERALCONFIG_MSPI_XIPCONFIG_MSPI_SCRAMBLECONFIG_MSPI_TIMINGCONFIG_MSPI_INIT_PRIORITYCONFIG_MSPI_COMPLETION_TIMEOUT_TOLERANCE
API Reference
mspi_interface Doxygen group이 MSPI interface의 공식 API reference를 제공합니다.
Source
출처
영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.